Request Binding
4 minute read
Request binding parses request data (query parameters, URL parameters, form data, JSON) into Go structs.
For simple cases, use the standard library’s json.Decoder. For full binding capabilities (query, form, headers, cookies, multi-source), use the separate binding package. For integrated binding with validation, use the app package.
Router Context Methods
The router Context provides basic data access methods and streaming capabilities.
Simple JSON Binding
For simple JSON binding in router-only code, use the standard library:
import "encoding/json"
r.POST("/users", func(c *router.Context) {
var req CreateUserRequest
if err := json.NewDecoder(c.Request.Body).Decode(&req); err != nil {
c.WriteErrorResponse(http.StatusBadRequest, "Invalid JSON")
return
}
c.JSON(201, req)
})
This works well for simple cases. For more features, use the binding package.
Manual Parameter Access
For simple cases, access parameters directly:
// Query parameters
r.GET("/search", func(c *router.Context) {
query := c.Query("q")
limit := c.QueryDefault("limit", "10")
c.JSON(200, map[string]string{
"query": query,
"limit": limit,
})
})
// URL parameters
r.GET("/users/:id", func(c *router.Context) {
userID := c.Param("id")
c.JSON(200, map[string]string{"user_id": userID})
})
// Form data
r.POST("/login", func(c *router.Context) {
username := c.FormValue("username")
password := c.FormValue("password")
// ...
})
Content Type Validation
Check the content type before processing the body:
r.POST("/users", func(c *router.Context) {
if !c.RequireContentTypeJSON() {
return // 415 Unsupported Media Type already sent
}
var req CreateUserRequest
if err := json.NewDecoder(c.Request.Body).Decode(&req); err != nil {
c.WriteErrorResponse(http.StatusBadRequest, "Invalid JSON")
return
}
c.JSON(201, req)
})
Streaming Large Payloads
For large arrays, stream instead of loading into memory:
// Stream JSON array items
r.POST("/bulk/users", func(c *router.Context) {
err := router.StreamJSONArray(c, func(user User) error {
return processUser(user)
}, 10000) // Max 10k items
if err != nil {
return
}
c.NoContent()
})
// Stream NDJSON (newline-delimited JSON)
r.POST("/import", func(c *router.Context) {
err := router.StreamNDJSON(c, func(item Record) error {
return importRecord(item)
})
if err != nil {
return
}
c.NoContent()
})
Binding Package (Full Features)
For comprehensive binding with struct tags, use the binding package:
import "rivaas.dev/binding"
// Bind query parameters to struct
type SearchRequest struct {
Query string `query:"q"`
Limit int `query:"limit" default:"10"`
Page int `query:"page" default:"1"`
}
r.GET("/search", func(c *router.Context) {
var req SearchRequest
if err := binding.Query(c.Request, &req); err != nil {
c.JSON(400, map[string]string{"error": err.Error()})
return
}
c.JSON(200, req)
})
Binding Methods (binding package)
binding.Query(r *http.Request, dst any) error // Query parameters
binding.Params(params map[string]string, dst any) error // URL parameters
binding.JSON(r *http.Request, dst any) error // JSON body
binding.Form(r *http.Request, dst any) error // Form data
binding.Headers(r *http.Request, dst any) error // Request headers
binding.Cookies(r *http.Request, dst any) error // Cookies
Supported Types
Primitives:
type Example struct {
String string `query:"string"`
Int int `query:"int"`
Int64 int64 `query:"int64"`
Float64 float64 `query:"float64"`
Bool bool `query:"bool"`
}
Time and Duration:
type Example struct {
Time time.Time `query:"time"` // RFC3339, ISO8601, etc.
Duration time.Duration `query:"duration"` // "5m", "1h30m", etc.
}
Network Types:
type Example struct {
IP net.IP `query:"ip"` // "192.168.1.1"
IPNet net.IPNet `query:"ipnet"` // "192.168.1.0/24"
URL url.URL `query:"url"` // "https://example.com"
}
Slices:
type Example struct {
Tags []string `query:"tags"` // ?tags=a&tags=b&tags=c
IDs []int `query:"ids"` // ?ids=1&ids=2&ids=3
}
Maps:
type Example struct {
// Dot notation: ?metadata.key1=value1&metadata.key2=value2
Metadata map[string]string `query:"metadata"`
// Bracket notation: ?filters[status]=active&filters[type]=post
Filters map[string]string `query:"filters"`
}
Struct Tags
enum - Enum Validation:
type Request struct {
Status string `query:"status" enum:"active,inactive,pending"`
}
default - Default Values:
type Request struct {
Limit int `query:"limit" default:"10"`
Sort string `query:"sort" default:"desc"`
}
Combined:
type Request struct {
Status string `query:"status" enum:"active,inactive" default:"active"`
Limit int `query:"limit" default:"10"`
}
Complete Example
package main
import (
"net/http"
"rivaas.dev/router"
"rivaas.dev/binding"
)
type CreateUserRequest struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
Tags []string `json:"tags"`
Metadata map[string]string `json:"metadata"`
}
type SearchRequest struct {
Query string `query:"q"`
Limit int `query:"limit" default:"10"`
Status string `query:"status" enum:"active,inactive,all" default:"all"`
}
func main() {
r := router.MustNew()
// Simple JSON binding
r.POST("/users", func(c *router.Context) {
var req CreateUserRequest
if err := json.NewDecoder(c.Request.Body).Decode(&req); err != nil {
c.WriteErrorResponse(http.StatusBadRequest, "Invalid JSON")
return
}
c.JSON(201, req)
})
// Query binding (using binding package)
r.GET("/search", func(c *router.Context) {
var req SearchRequest
if err := binding.Query(c.Request, &req); err != nil {
c.JSON(400, map[string]string{"error": err.Error()})
return
}
c.JSON(200, req)
})
// Simple parameter access
r.GET("/users/:id", func(c *router.Context) {
userID := c.Param("id")
includeDeleted := c.QueryDefault("include_deleted", "false")
c.JSON(200, map[string]string{
"user_id": userID,
"include_deleted": includeDeleted,
})
})
http.ListenAndServe(":8080", r)
}
Next Steps
- Binding Package: Full binding documentation at binding guide
- Validation: Learn about request validation
- Examples: See complete examples with binding
- API Reference: Check binding API reference
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.