Skip to main content

Validation

Zen provides a pluggable Validator interface with a built-in default backed by go-playground/validator and familiar tag-based rules.

Validator Interface

type Validator interface {
Validate(i any) error
}

Implement this to plug in any validation library. The default uses go-playground/validator/v10 with validate struct tags.

Manual Validation

Validation is off by default. After binding, call zen.Validate() explicitly:

type SignupRequest struct {
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8"`
Age int `json:"age" validate:"gte=18"`
}

r.POST("/signup", func(c *zen.Ctx) {
var req SignupRequest
if err := c.BindJSON(&req); err != nil {
c.Error(400, err.Error())
return
}
if err := zen.Validate(&req); err != nil {
c.Error(400, err.Error())
return
}
// req is valid - proceed
})

Auto-Validation

Call EnableAutoValidation() once at startup to have BindJSON, BindXML, and BindForm run validation automatically after decoding:

zen.EnableAutoValidation()

r.POST("/signup", func(c *zen.Ctx) {
var req SignupRequest
if err := c.BindJSON(&req); err != nil {
c.Error(400, err.Error())
return
}
// req is already validated - proceed
})

Custom Validation Tags

Register custom validation rules:

zen.DefaultValidator().RegisterValidation("is-even", func(fl validator.FieldLevel) bool {
return fl.Field().Int()%2 == 0
})

type Request struct {
Value int64 `json:"value" validate:"is-even"`
}

Returns nil if you swapped in a custom validator via SetValidator.

Custom Validator

Swap in any validator by implementing the interface:

type CustomValidator struct {
validator *validator.Validate
}

func (cv *CustomValidator) Validate(i any) error {
return cv.validator.Struct(i)
}

zen.SetValidator(&CustomValidator{
validator: validator.New(),
})

Pass nil to disable validation entirely:

zen.SetValidator(nil)

Supported Validators

TagRule
requiredField must be non-zero
min=NMinimum length/value
max=NMaximum length/value
emailFast regex email check
gte=NGreater than or equal
lte=NLess than or equal
len=NExact length