API Reference

Complete API documentation for all types, functions, and interfaces

Detailed API reference for all exported types, functions, and interfaces in the rivaas.dev/binding package.

Core Binding Functions

Generic API

JSON

func JSON[T any](data []byte, opts ...Option) (T, error)

Binds JSON data to a struct of type T.

Parameters:

  • data: JSON bytes to parse
  • opts: Optional configuration options

Returns:

  • Populated struct of type T
  • Error if binding fails

Example:

type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

user, err := binding.JSON[User](jsonData)

JSONReader

func JSONReader[T any](r io.Reader, opts ...Option) (T, error)

Binds JSON from an io.Reader. More memory-efficient for large payloads.

Example:

user, err := binding.JSONReader[User](r.Body)

Query

func Query[T any](values url.Values, opts ...Option) (T, error)

Binds URL query parameters to a struct.

Parameters:

  • values: URL query values (r.URL.Query())
  • opts: Optional configuration options

Example:

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

params, err := binding.Query[Params](r.URL.Query())

Form

func Form[T any](values url.Values, opts ...Option) (T, error)

Binds form data to a struct.

Parameters:

  • values: Form values (r.Form or r.PostForm)
  • opts: Optional configuration options

Example:

type LoginForm struct {
    Username string `form:"username"`
    Password string `form:"password"`
}

form, err := binding.Form[LoginForm](r.PostForm)
func Header[T any](headers http.Header, opts ...Option) (T, error)

Binds HTTP headers to a struct.

Example:

type Headers struct {
    APIKey    string `header:"X-API-Key"`
    RequestID string `header:"X-Request-ID"`
}

headers, err := binding.Header[Headers](r.Header)
func Cookie[T any](cookies []*http.Cookie, opts ...Option) (T, error)

Binds HTTP cookies to a struct.

Example:

type Cookies struct {
    SessionID string `cookie:"session_id"`
    Theme     string `cookie:"theme" default:"light"`
}

cookies, err := binding.Cookie[Cookies](r.Cookies())

Path

func Path[T any](params map[string]string, opts ...Option) (T, error)

Binds URL path parameters to a struct.

Example:

type PathParams struct {
    UserID int `path:"user_id"`
}

// With gorilla/mux or chi
params, err := binding.Path[PathParams](mux.Vars(r))

XML

func XML[T any](data []byte, opts ...Option) (T, error)

Binds XML data to a struct.

Example:

type Document struct {
    Title string `xml:"title"`
    Body  string `xml:"body"`
}

doc, err := binding.XML[Document](xmlData)

XMLReader

func XMLReader[T any](r io.Reader, opts ...Option) (T, error)

Binds XML from an io.Reader.

Bind (Multi-Source)

func Bind[T any](sources ...Source) (T, error)

Binds from multiple sources with precedence.

Example:

type Request struct {
    UserID int    `query:"user_id" json:"user_id"`
    APIKey string `header:"X-API-Key"`
}

req, err := binding.Bind[Request](
    binding.FromQuery(r.URL.Query()),
    binding.FromJSON(r.Body),
    binding.FromHeader(r.Header),
)

Non-Generic API

JSONTo

func JSONTo(data []byte, target interface{}, opts ...Option) error

Binds JSON to a pointer. Use when type comes from a variable.

Example:

var user User
err := binding.JSONTo(jsonData, &user)

Similar non-generic functions exist for all sources:

  • QueryTo(values url.Values, target interface{}, opts ...Option) error
  • FormTo(values url.Values, target interface{}, opts ...Option) error
  • HeaderTo(headers http.Header, target interface{}, opts ...Option) error
  • CookieTo(cookies []*http.Cookie, target interface{}, opts ...Option) error
  • PathTo(params map[string]string, target interface{}, opts ...Option) error
  • XMLTo(data []byte, target interface{}, opts ...Option) error

Source Constructors

For multi-source binding:

func FromJSON(r io.Reader) Source
func FromQuery(values url.Values) Source
func FromForm(values url.Values) Source
func FromHeader(headers http.Header) Source
func FromCookie(cookies []*http.Cookie) Source
func FromPath(params map[string]string) Source
func FromXML(r io.Reader) Source

Binder Type

Constructor

func New(opts ...Option) (*Binder, error)
func MustNew(opts ...Option) *Binder

Creates a reusable binder with configuration.

Example:

binder := binding.MustNew(
    binding.WithConverter[uuid.UUID](uuid.Parse),
    binding.WithMaxDepth(16),
)

user, err := binder.JSON[User](data)

Binder Methods

A Binder has the same methods as the package-level functions:

func (b *Binder) JSON[T any](data []byte, opts ...Option) (T, error)
func (b *Binder) Query[T any](values url.Values, opts ...Option) (T, error)
// ... etc for all binding functions

Error Types

BindError

Field-specific binding error with detailed context:

type BindError struct {
    Field  string // Field name that failed to bind
    Source string // Source ("query", "json", "header", etc.)
    Value  string // Raw value that failed to bind
    Type   string // Expected Go type
    Reason string // Human-readable reason
    Err    error  // Underlying error
}

func (e *BindError) Error() string
func (e *BindError) Unwrap() error
func (e *BindError) IsType() bool    // True if type conversion failed
func (e *BindError) IsMissing() bool // True if required field missing

Example:

user, err := binding.JSON[User](data)
if err != nil {
    var bindErr *binding.BindError
    if errors.As(err, &bindErr) {
        log.Printf("Field %s from %s failed: %v",
            bindErr.Field, bindErr.Source, bindErr.Err)
    }
}

UnknownFieldError

Returned in strict mode when unknown fields are encountered:

type UnknownFieldError struct {
    Fields []string // List of unknown field names
}

func (e *UnknownFieldError) Error() string

Example:

user, err := binding.JSON[User](data, binding.WithStrictJSON())
if err != nil {
    var unknownErr *binding.UnknownFieldError
    if errors.As(err, &unknownErr) {
        log.Printf("Unknown fields: %v", unknownErr.Fields)
    }
}

MultiError

Multiple errors collected with WithAllErrors():

type MultiError struct {
    Errors []*BindError
}

func (e *MultiError) Error() string
func (e *MultiError) Unwrap() []error

Example:

user, err := binding.JSON[User](data, binding.WithAllErrors())
if err != nil {
    var multi *binding.MultiError
    if errors.As(err, &multi) {
        for _, e := range multi.Errors {
            log.Printf("Field %s: %v", e.Field, e.Err)
        }
    }
}

Interfaces

ValueGetter

Interface for custom data sources:

type ValueGetter interface {
    Get(key string) string          // Get first value for key
    GetAll(key string) []string     // Get all values for key
    Has(key string) bool            // Check if key exists
}

Example Implementation:

type EnvGetter struct{}

func (g *EnvGetter) Get(key string) string {
    return os.Getenv(key)
}

func (g *EnvGetter) GetAll(key string) []string {
    if val := os.Getenv(key); val != "" {
        return []string{val}
    }
    return nil
}

func (g *EnvGetter) Has(key string) bool {
    _, exists := os.LookupEnv(key)
    return exists
}

ConverterFunc

Function type for custom type converters:

type ConverterFunc[T any] func(string) (T, error)

Example:

func ParseEmail(s string) (Email, error) {
    if !strings.Contains(s, "@") {
        return "", errors.New("invalid email")
    }
    return Email(s), nil
}

binder := binding.MustNew(
    binding.WithConverter[Email](ParseEmail),
)

Helper Functions

MapGetter

Converts a map[string]string to a ValueGetter:

func MapGetter(m map[string]string) ValueGetter

Example:

data := map[string]string{"name": "Alice", "age": "30"}
getter := binding.MapGetter(data)
result, err := binding.RawInto[User](getter, "custom")

MultiMapGetter

Converts a map[string][]string to a ValueGetter:

func MultiMapGetter(m map[string][]string) ValueGetter

Example:

data := map[string][]string{
    "tags": {"go", "rust"},
    "name": {"Alice"},
}
getter := binding.MultiMapGetter(data)
result, err := binding.RawInto[User](getter, "custom")

GetterFunc

Adapts a function to the ValueGetter interface:

type GetterFunc func(key string) ([]string, bool)

func (f GetterFunc) Get(key string) string
func (f GetterFunc) GetAll(key string) []string
func (f GetterFunc) Has(key string) bool

Example:

getter := binding.GetterFunc(func(key string) ([]string, bool) {
    if val, ok := myMap[key]; ok {
        return []string{val}, true
    }
    return nil, false
})

Raw/RawInto

Low-level binding from custom ValueGetter:

func Raw[T any](getter ValueGetter, source string, opts ...Option) (T, error)
func RawInto(getter ValueGetter, source string, target interface{}, opts ...Option) error

Events and Observability

Events Type

Hooks for observing binding operations:

type Events struct {
    FieldBound   func(name, tag string)
    UnknownField func(name string)
    Done         func(stats Stats)
}

Example:

binder := binding.MustNew(
    binding.WithEvents(binding.Events{
        FieldBound: func(name, tag string) {
            log.Printf("Bound field %s from %s", name, tag)
        },
        UnknownField: func(name string) {
            log.Printf("Unknown field: %s", name)
        },
        Done: func(stats binding.Stats) {
            log.Printf("Binding completed: %d fields, %d errors",
                stats.FieldsBound, stats.ErrorCount)
        },
    }),
)

Stats Type

Statistics from binding operation:

type Stats struct {
    FieldsBound int           // Number of fields successfully bound
    ErrorCount  int           // Number of errors encountered
    Duration    time.Duration // Time taken for binding
}

Constants

Slice Modes

const (
    SliceRepeat SliceMode = iota // Repeated params: ?tags=a&tags=b (default)
    SliceCSV                     // CSV params: ?tags=a,b,c
)

Unknown Field Handling

const (
    UnknownIgnore UnknownMode = iota // Ignore unknown fields (default)
    UnknownWarn                       // Log warning for unknown fields
    UnknownError                      // Error on unknown fields
)

Merge Strategies

const (
    MergeLastWins  MergeStrategy = iota // Last source wins (default)
    MergeFirstWins                       // First source wins
)

Default Values

Time Layouts

var DefaultTimeLayouts = []string{
    time.RFC3339,
    time.RFC3339Nano,
    time.RFC1123,
    time.RFC1123Z,
    time.RFC822,
    time.RFC822Z,
    time.RFC850,
    time.ANSIC,
    time.UnixDate,
    time.RubyDate,
    time.Kitchen,
    time.Stamp,
    time.StampMilli,
    time.StampMicro,
    time.StampNano,
    time.DateTime,
    time.DateOnly,
    time.TimeOnly,
    "2006-01-02",
    "01/02/2006",
    "2006/01/02",
}

Can be extended with WithTimeLayouts().

Type Constraints

Supported Interface Types

Types implementing these interfaces are automatically supported:

  • encoding.TextUnmarshaler: For custom text unmarshaling
  • json.Unmarshaler: For custom JSON unmarshaling
  • xml.Unmarshaler: For custom XML unmarshaling

Example:

type Status string

func (s *Status) UnmarshalText(text []byte) error {
    // Custom parsing logic
    *s = Status(string(text))
    return nil
}

type Request struct {
    Status Status `query:"status"` // Automatically uses UnmarshalText
}

Thread Safety

All package-level functions and Binder methods are safe for concurrent use. The struct reflection cache is thread-safe and has no size limit.

See Also

For usage examples, see the Binding Guide.