Parameter Binding
Parameter Binding
Section titled “Parameter Binding”Fox automatically binds request parameters from various sources to your handler function parameters.
Supported Sources
Section titled “Supported Sources”Fox can bind parameters from:
- URI path parameters -
/user/:id(usinguritag) - Query strings -
?name=value(usingqueryorformtag) - JSON request body -
Content-Type: application/json(usingjsontag) - Form data -
Content-Type: application/x-www-form-urlencoded(usingformtag) - Headers - Custom HTTP headers (using
headertag)
Basic Usage
Section titled “Basic Usage”URI Parameters
Section titled “URI Parameters”type UserRequest struct { ID int `uri:"id" binding:"required"`}
r.GET("/user/:id", func(req *UserRequest) (*User, error) { return getUserByID(req.ID)})Query Parameters
Section titled “Query Parameters”Fox supports both form and query tags for binding URL query parameters:
type SearchRequest struct { Query string `query:"q" binding:"required"` // Using query tag Page int `query:"page"` Size int `query:"size"`}
// Or use form tag (both work the same way)type SearchRequest struct { Query string `form:"q" binding:"required"` // Using form tag Page int `form:"page"` Size int `form:"size"`}
r.GET("/search", func(req *SearchRequest) ([]Result, error) { return search(req.Query, req.Page, req.Size)})JSON Body
Section titled “JSON Body”type CreateUserRequest struct { Name string `json:"name" binding:"required"` Email string `json:"email" binding:"required,email"` Age int `json:"age" binding:"gte=0,lte=130"` Password string `json:"password" binding:"required,min=8"`}
r.POST("/users", func(req *CreateUserRequest) (*User, error) { return createUser(req)})Multiple Sources
Section titled “Multiple Sources”Bind from multiple sources in a single struct:
type UpdateUserRequest struct { ID int `uri:"id" binding:"required"` // From path Name string `json:"name" binding:"required"` // From JSON body AuthUser string `header:"X-Auth-User" binding:"required"` // From header}
r.PUT("/user/:id", func(req *UpdateUserRequest) error { return updateUser(req.ID, req.Name, req.AuthUser)})Validation Tags
Section titled “Validation Tags”Fox uses the validator library for validation:
Common Tags
Section titled “Common Tags”type UserInput struct { // Required field Name string `json:"name" binding:"required"`
// Email validation Email string `json:"email" binding:"required,email"`
// Length constraints Username string `json:"username" binding:"required,min=3,max=20"`
// Numeric range Age int `json:"age" binding:"gte=0,lte=130"`
// URL validation Website string `json:"website" binding:"omitempty,url"`
// Enum validation Role string `json:"role" binding:"required,oneof=admin user guest"`
// Custom regex Phone string `json:"phone" binding:"required,e164"` // E.164 phone format}Nested Structs
Section titled “Nested Structs”type Address struct { Street string `json:"street" binding:"required"` City string `json:"city" binding:"required"` Country string `json:"country" binding:"required,iso3166_1_alpha2"`}
type CreateUserRequest struct { Name string `json:"name" binding:"required"` Email string `json:"email" binding:"required,email"` Address Address `json:"address" binding:"required"`}Slice Validation
Section titled “Slice Validation”type BatchRequest struct { IDs []int `json:"ids" binding:"required,min=1,max=100,dive,gte=1"` Emails []string `json:"emails" binding:"required,dive,email"`}The dive tag validates each element in the slice.
Optional Parameters
Section titled “Optional Parameters”Use omitempty for optional fields:
type FilterRequest struct { Name string `form:"name"` // Optional, no validation Category string `form:"category" binding:"omitempty,oneof=books electronics"` MinPrice *int `form:"min_price" binding:"omitempty,gte=0"`}Default Values
Section titled “Default Values”Set default values in struct initialization:
type PaginationRequest struct { Page int `form:"page"` Size int `form:"size"`}
r.GET("/items", func(req *PaginationRequest) ([]Item, error) { // Set defaults if not provided if req.Page == 0 { req.Page = 1 } if req.Size == 0 { req.Size = 20 }
return getItems(req.Page, req.Size)})Error Handling
Section titled “Error Handling”When binding or validation fails, Fox automatically returns a 400 error with details:
{ "error": "Key: 'CreateUserRequest.Email' Error:Field validation for 'Email' failed on the 'email' tag"}Custom Error Messages
Section titled “Custom Error Messages”Implement custom error handling:
r.SetErrorHandler(func(c *gin.Context, err error) { if validationErr, ok := err.(validator.ValidationErrors); ok { errors := make(map[string]string) for _, e := range validationErr { errors[e.Field()] = fmt.Sprintf("validation failed on '%s'", e.Tag()) } c.JSON(400, gin.H{"errors": errors}) return } c.JSON(500, gin.H{"error": err.Error()})})Type Conversion
Section titled “Type Conversion”Fox automatically converts string parameters to the target type:
type Request struct { ID int `uri:"id"` // "123" -> 123 Active bool `form:"active"` // "true" -> true Price float64 `form:"price"` // "19.99" -> 19.99 Date time.Time `form:"date" time_format:"2006-01-02"`}Best Practices
Section titled “Best Practices”- Always validate required fields - Use
binding:"required"for mandatory parameters - Use specific validation tags - Be explicit about constraints (
min,max,email, etc.) - Document your structs - Add comments explaining fields and validation rules
- Use pointers for optional fields - Distinguish between “not provided” and “zero value”
- Keep structs focused - Create separate request structs for different operations
Next Steps
Section titled “Next Steps”- Validation - Custom validation rules
- Multi-Domain Routing - Route by domain