Validator Documentation
The validators
package is used to ensure that incoming request data is valid according to predefined rules. The package integrates with the API to perform validation checks before the request is processed further.
Overview
Each incoming request body is validated using a set of validation rules defined in the struct tags. The validation is performed automatically by the WithBody
middleware before passing control to the corresponding handler.
Example: Register Request
Here’s an example of a RegisterRequest
struct with validation rules:
type RegisterRequest struct {
Email string `json:"email" validate:"nonzero,email"`
Username string `json:"username" validate:"min=2,max=40,regexp=^[a-zA-Z]*$"`
Password string `json:"password" validate:"max=256,password"`
}
In this example:
Email
must be non-empty and a valid email format.Username
must be between 2 and 40 characters long and only contain alphabetic characters.Password
must not exceed 256 characters and must meet certain password criteria (such as length, type).
The validation rules are specified using tags in the struct definition, following the syntax supported by the validator library.
How It Works
The validation process is integrated into the request handling using a middleware function. The middleware automatically checks the request body against the validation rules defined in the model struct.
WithBody
Middleware
The WithBody
middleware is responsible for:
- Parsing the body: It unmarshals the incoming JSON request body into the specified struct (
K
). - Validating the body: It validates the parsed struct using the
validator.Validate
function. If the body does not meet the validation rules, the middleware returns a400 Bad Request
response with the corresponding error messages. - Calling the handler: If the body passes validation, the middleware calls the original handler with the validated data.
Here is the middleware function:
func WithBody[K any](fn func(api *Api) func(ctx *atreugo.RequestCtx, body K) error) func(api *Api) func(ctx *atreugo.RequestCtx) error {
return func(api *Api) func(ctx *atreugo.RequestCtx) error {
return func(ctx *atreugo.RequestCtx) error {
var body K
if err := json.Unmarshal(ctx.PostBody(), &body); err != nil {
logrus.
WithField("request_ip", ctx.RemoteIP().String()).
WithError(err).
Warn("bad request")
return ctx.JSONResponse(NewErrorResponse(400, []ResponseError{{Message: "Bad request"}}))
}
if err := validator.Validate(body); err != nil {
logrus.
WithField("request_ip", ctx.RemoteIP().String()).
WithError(err).
Warn("invalid request")
return ctx.JSONResponse(NewErrorResponse(400, validatorErrorToResponseError(err)))
}
return fn(api)(ctx, body)
}
}
}
Example of Usage in a Route
You can use the WithBody
middleware to validate the request body in your routes. For example, in the register
route:
group.POST("/register", WithDefaults(api, WithBody(register)))
func register(api *Api) func(ctx *atreugo.RequestCtx, rr *RegisterRequest) error {
return func(ctx *atreugo.RequestCtx, rr *RegisterRequest) error {
// handler logic
}
}
In this example, the register
handler receives a RegisterRequest
object that has already been validated.
Validator Rules
For default validators, check out the package's documentation
email
: Ensures the field is a valid email address.password
: Custom password validation rule that include checks for complexity and length.
Error Handling
If validation fails, the middleware will log the error and return a 400 Bad Request
response with detailed error messages. The validatorErrorToResponseError
function formats the validation errors into a response-friendly format.
Example error response:
{
"status": 400,
"errors": [
{
"field": "Email",
"message": "Email must be a valid email address"
}
]
}
Best Practices
- Use specific validation rules: Apply the correct validation rule to each field (e.g.,
email
,min
,max
,regexp
). - Limit validation complexity: Keep the validation rules simple and focused to avoid unnecessary overhead in request processing.
- Log validation errors: Ensure that all validation errors are logged to help with debugging and monitoring.