Request Data Binding

Learn how to bind HTTP request data to Go structs with type safety and performance

The Rivaas Binding package provides high-performance request data binding for Go web applications. It maps values from various sources (query parameters, form data, JSON bodies, headers, cookies, path parameters) into Go structs using struct tags.

Features

  • Multiple Sources - Query, path, form, multipart, header, cookie, JSON, XML, YAML, TOML, MessagePack, Protocol Buffers
  • File Uploads - Handle file uploads with multipart forms seamlessly
  • Type Safe - Generic API for compile-time type safety
  • Zero Allocation - Struct reflection info cached for performance
  • Flexible - Nested structs, slices, maps, pointers, custom types
  • Error Context - Detailed field-level error information
  • Extensible - Custom type converters and value getters

Quick Start

import "rivaas.dev/binding"

type CreateUserRequest struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    Age   int    `json:"age"`
}

// Generic API (preferred)
user, err := binding.JSON[CreateUserRequest](body)
if err != nil {
    // Handle error
}
import "rivaas.dev/binding"

type ListParams struct {
    Page   int      `query:"page" default:"1"`
    Limit  int      `query:"limit" default:"20"`
    Tags   []string `query:"tags"`
    SortBy string   `query:"sort_by"`
}

params, err := binding.Query[ListParams](r.URL.Query())
import "rivaas.dev/binding"

type CreateOrderRequest struct {
    // From path parameters
    UserID int `path:"user_id"`
    
    // From query string
    Coupon string `query:"coupon"`
    
    // From headers
    Auth string `header:"Authorization"`
    
    // From JSON body
    Items []OrderItem `json:"items"`
    Total float64     `json:"total"`
}

req, err := binding.Bind[CreateOrderRequest](
    binding.FromPath(pathParams),
    binding.FromQuery(r.URL.Query()),
    binding.FromHeader(r.Header),
    binding.FromJSON(body),
)

Learning Path

Follow these guides to master request data binding with Rivaas:

  1. Installation - Get started with the binding package
  2. Basic Usage - Learn the fundamentals of binding data
  3. Query Parameters - Work with URL query strings
  4. JSON Binding - Handle JSON request bodies
  5. Multipart Forms - Handle file uploads with form data
  6. Multi-Source - Combine data from multiple sources
  7. Struct Tags - Master struct tag syntax and options
  8. Type Support - Built-in and custom type conversion
  9. Error Handling - Handle binding errors gracefully
  10. Advanced Usage - Custom getters, streaming, and more
  11. Examples - Real-world integration patterns

Supported Sources

SourceFunctionDescription
QueryQuery[T]()URL query parameters (?name=value)
PathPath[T]()URL path parameters (/users/:id)
FormForm[T]()Form data (application/x-www-form-urlencoded)
MultipartMultipart[T]()Multipart form data with file uploads
HeaderHeader[T]()HTTP headers
CookieCookie[T]()HTTP cookies
JSONJSON[T]()JSON body
XMLXML[T]()XML body
YAMLyaml.YAML[T]()YAML body (sub-package)
TOMLtoml.TOML[T]()TOML body (sub-package)
MessagePackmsgpack.MsgPack[T]()MessagePack body (sub-package)
Protocol Buffersproto.Proto[T]()Protobuf body (sub-package)

Why Generic API?

The binding package uses Go generics for compile-time type safety:

// Generic API (preferred) - Type-safe at compile time
user, err := binding.JSON[CreateUserRequest](body)

// Non-generic API - When type comes from variable
var user CreateUserRequest
err := binding.JSONTo(body, &user)

Benefits:

  • ✅ Compile-time type checking
  • ✅ No reflection overhead for type instantiation
  • ✅ Better IDE autocomplete
  • ✅ Cleaner, more readable code

Performance

  • First binding of a type: ~500ns overhead for reflection
  • Subsequent bindings: ~50ns overhead (cache lookup)
  • Query/Path/Form: Zero allocations for primitive types
  • Struct reflection info cached automatically

Next Steps

For integration with rivaas/app, the Context provides a convenient Bind() method that handles all the complexity automatically.