Validators
The validators package provides input validation built on go-playground/validator/v10 . It uses struct tag-based validation with custom validators registered at startup, and produces translated error messages.
Import
import "github.com/gofastadev/gofasta/pkg/validators"Key Types
AppValidator
type AppValidator struct {
Validate *validator.Validate
Trans ut.Translator
}Key Functions
| Function | Signature | Description |
|---|---|---|
NewAppValidator | func NewAppValidator(db *gorm.DB) *AppValidator | Creates a validator with common validations registered |
ValidateStruct | func (v *AppValidator) ValidateStruct(input interface{}) []*types.TCommonAPIErrorDto | Validates the input struct and returns validation errors |
RegisterCommonValidators | func RegisterCommonValidators(validate *validator.Validate, db *gorm.DB) | Registers the gofasta library’s common validators on an existing validator instance |
RegisterTranslation | func RegisterTranslation(v *validator.Validate, trans ut.Translator, tag string, message string) | Registers a custom validation error message |
Built-in Custom Validators
These validators are registered automatically when using NewAppValidator and can be used as struct tags:
| Tag | Description |
|---|---|
uuid4_valid | Must be a valid UUID v4 |
is_record_deletable | Record must be deletable (checks is_deletable column) |
is_record_exist_by_name_for_conflict | Name must not already exist in the specified table |
does_record_exist_by_id_for_verification | ID must exist in the specified table |
is_valid_url | Must be a valid HTTP or HTTPS URL |
In addition, all standard go-playground/validator tags are available (required, email, min, max, gte, lte, etc.).
Usage
Setting Up the Validator
The AppValidator is created once at startup and shared across your application:
appValidator := validators.NewAppValidator(db)Defining Validation with Struct Tags
type CreateUserInput struct {
Name string `json:"name" validate:"required,min=2,max=100"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8"`
Role string `json:"role" validate:"required,oneof=admin editor viewer"`
Website *string `json:"website" validate:"omitempty,is_valid_url"`
}Validating in a Controller
func (c *UserController) Create(w http.ResponseWriter, r *http.Request) {
var input CreateUserInput
if err := httputil.Bind(r, &input); err != nil {
httputil.Error(w, errors.BadRequest(err.Error()))
return
}
if valErrs := c.validator.ValidateStruct(input); len(valErrs) > 0 {
httputil.JSON(w, http.StatusBadRequest, types.TCommonResponseDto{
Status: http.StatusBadRequest,
Errors: valErrs,
})
return
}
user, err := c.service.Create(r.Context(), input)
if err != nil {
httputil.Error(w, err)
return
}
httputil.Created(w, user)
}The error response looks like:
{
"status": 400,
"errors": [
{"fieldName": "email", "message": "Email must be a valid email address"},
{"fieldName": "password", "message": "Password must be at least 8 characters in length"}
]
}Database Uniqueness Check
Use the is_record_exist_by_name_for_conflict tag with the table name as a parameter:
type CreateCategoryInput struct {
Name string `json:"name" validate:"required,is_record_exist_by_name_for_conflict=categories"`
}Record Existence Verification
type AssignRoleInput struct {
RoleID string `json:"roleId" validate:"required,uuid4_valid,does_record_exist_by_id_for_verification=roles"`
}Registering Custom Validators
Extend the validator by registering additional validations on the Validate field:
appValidator := validators.NewAppValidator(db)
// Register a custom validation
appValidator.Validate.RegisterValidation("strong_password", func(fl validator.FieldLevel) bool {
password := fl.Field().String()
hasUpper := regexp.MustCompile(`[A-Z]`).MatchString(password)
hasLower := regexp.MustCompile(`[a-z]`).MatchString(password)
hasDigit := regexp.MustCompile(`[0-9]`).MatchString(password)
return hasUpper && hasLower && hasDigit
})
// Register a translation for the custom validation
validators.RegisterTranslation(appValidator.Validate, appValidator.Trans,
"strong_password", "{0} must contain uppercase, lowercase, and digit characters")Then use it in struct tags:
type ResetPasswordInput struct {
Password string `json:"password" validate:"required,min=8,strong_password"`
}Related Pages
- Errors — Validation errors map to structured error responses
- HTTP Utilities — Bind and validate request input
- Types — Shared DTO types including TCommonAPIErrorDto
Last updated on