Validation
gin-kit validates request DTOs with
go-playground/validator behind
an explicit wrapper (runtime/validation, vendored as
internal/platform/validation in standalone projects). Failures are reported by
JSON/form field name with human-readable messages and named parameters —
never the submitted values.
{ "fields": { "age": [ { "rule": "gte", "message": "The age field must be at least 18.", "parameters": { "min": "18" } } ] }}Built-in messages
Section titled “Built-in messages”Any validate tag the underlying engine supports will work; these rules ship
with polished English messages and named parameters out of the box:
| Rule | Message | Parameter |
|---|---|---|
required |
The X field is required. | — |
email |
The X field must be a valid email address. | — |
min |
The X field must be at least N. | min |
max |
The X field must not be greater than N. | max |
len |
The X field must contain exactly N items. | length |
oneof |
The selected X is invalid. | allowed |
gte / lte |
must be at least / must not be greater than | min / max |
gt / lt |
must be greater than / less than | greater_than / less_than |
url |
The X field must be a valid URL. | — |
uuid |
The X field must be a valid UUID. | — |
numeric |
The X field must be a number. | — |
alphanum |
The X field must only contain letters and numbers. | — |
datetime |
The X field must match the LAYOUT format. | layout |
eqfield |
The X field must match the OTHER field. | other |
ne |
The X field must not be VALUE. | disallowed |
startswith / endswith |
must start with / must end with | prefix / suffix |
Rules without a listed message fall back to “The X field is invalid.” — register a message (below) when you use them.
Which validator runs
Section titled “Which validator runs”The httpx binders resolve the validator in a fixed order:
- An explicit argument:
httpx.BindJSON[T](c, myValidator). - The application validator from
runtime.Options.Validator— the runtime places it on the request context, so rules registered throughapp.Validator()apply to every binder with no extra wiring. validation.Defaultas the fallback (plaingin.Enginein tests, and always in standalone projects, wherevalidation.Defaultis the application validator).
Custom rules, messages, and translations
Section titled “Custom rules, messages, and translations”v := validation.New()
// A domain-specific rule.err := v.RegisterRule("slug", func(fl validator.FieldLevel) bool { return !strings.Contains(fl.Field().String(), " ")})
// Its message. {field} and {parameter} expand at render time.v.RegisterMessage("slug", "The {field} field must not contain spaces.")
app, err := runtime.New(runtime.Options{Validator: v})Every handler using httpx.BindJSON/BindQuery/BindURI now enforces
validate:"slug" and renders the custom message. To localize all messages,
replace the translator:
v.SetTranslator(func(c validation.Context) string { // c.Field, c.Rule, c.Parameter return messagesByRule[c.Rule](c)})Validating outside a binder works too — the UI-mode form handlers do exactly this:
request.Normalize()if err := validation.Default.Struct(request); err != nil { var failures *validation.Errors if errors.As(err, &failures) { /* failures.Fields */ }}See Responses and validation for the HTTP
contract these failures render as, and
Request and response DTOs for where validate tags live.

