API reference
The whole exported surface of uradical.io/go/binder: two
functions, four types, one constant and five sentinel errors. The
generated reference lives at
pkg.go.dev;
this page is the same material with the reasoning attached.
Functions
Bindfunc
func Bind(r *http.Request, i any) error
Binds an HTTP request into the struct i points at. The
target must be a non-nil pointer to a struct; anything else is
ErrInvalidTarget. Bodies are capped at
DefaultMaxBodySize.
Every field is attempted, and every field that fails is reported
together as BindErrors. Fields
reflection cannot set — unexported ones — are ignored even when they
carry a tag. If the target implements
Validator, Validate
runs once every field has bound, and its error is returned.
Returns an error when
- any field fails to bind —
BindErrors, one entry per failure, whether a value would not convert, arequiredvalue was missing (ErrMissingRequired) or, withDisallowUnknownFields, the body carried a key nothing binds (ErrUnknownField); - the target is not a non-nil pointer to a struct —
ErrInvalidTarget; - the body exceeded the size limit —
ErrBodyTooLarge; - the body could not be parsed —
ErrMalformedBody; - the request was nil, or the target has a field that cannot be bound, such as a pointer type that points to itself, or one tagged
binding,uriorparamfor another framework —ErrInvalidTarget; - the body could not be read at all, such as when the client disconnected — the I/O error, wrapped;
Validatefailed — its error, wrapped.
BindWithOptionsfunc
func BindWithOptions(r *http.Request, i any, opts BindOptions) error
Bind with per-call configuration. The zero
BindOptions behaves exactly as Bind does, so
only the fields you care about need setting — a larger body limit on an
upload endpoint, say, without touching any other.
A nil request is ErrInvalidTarget rather than a panic.
Types
BindOptionstype
type BindOptions struct {
// MaxBodySize is the largest request body, in bytes, this call reads.
// Zero applies DefaultMaxBodySize, and a negative value removes the limit.
MaxBodySize int64
// DisallowUnknownFields reports each top-level body key that no field of
// the target binds, as a BindErrors entry wrapping ErrUnknownField. Keys
// nested inside objects are not inspected.
DisallowUnknownFields bool
}See Options for how each behaves.
BindErrortype
type BindError struct {
Field string // Go field, as a path when nested: Address.Postcode, Tags[2]
Source string // tag source the value was read from, such as "query"
Name string // key the client sent, as a path when nested: address.postcode
Message string // description for logs; its wording is not stable
Err error // cause: ErrMissingRequired, ErrUnknownField or a conversion error
}
func (e *BindError) Error() string
func (e *BindError) Unwrap() error
One failure: a field that could not be bound, or a body member no field
binds. Key client-facing output on Name, the key as the
client sent it; it is empty only for an unknown member whose name was
itself empty. Field is the Go-side name for logs, and is empty for
an unknown body member, since no field binds it. See
Error handling.
BindErrorstype
type BindErrors []*BindError
func (e BindErrors) Error() string // one line per failure
func (e BindErrors) Unwrap() []error
What Bind returns when any field fails, whether one or
several — the same shape either way, so a handler has one path. Entries
follow the order the struct declares its fields, then any unknown body
members, and there are at most 100 of them. Unwrap exposes each entry, so
errors.Is(err, ErrMissingRequired) reports whether any
field was missing. Reach it with errors.As.
Validatortype
type Validator interface {
Validate(ctx context.Context) error
}
Implemented by a target that wants its own rules run once binding
succeeds. Bind passes the request's context. See
Validation.
Constants
DefaultMaxBodySizeconst
const DefaultMaxBodySize int64 = 10 << 20 // 10 MB
The largest body Bind reads, and the limit
BindWithOptions applies when MaxBodySize is
zero. A larger body is rejected with ErrBodyTooLarge
rather than buffered. Its value is not part of the
compatibility contract; pass BindOptions.MaxBodySize if
your service depends on a particular limit.
Sentinel errors
Match these with errors.Is. The message text is not stable; these are.
| Sentinel | Returned when |
|---|---|
ErrMalformedBody | The body could not be parsed as the format its Content-Type declares. |
ErrBodyTooLarge | The body exceeded the size limit. |
ErrInvalidTarget | The target was not a non-nil pointer to a struct, the request was nil, or the target has a field that cannot be bound, such as a pointer type that points to itself, or one tagged binding, uri or param for another framework. |
ErrMissingRequired | A field tagged required had no value. Carried by a BindErrors entry. |
ErrUnknownField | DisallowUnknownFields was set and the body carried a key nothing binds. Carried by a BindErrors entry. |
Struct tag summary
| Tag | Source |
|---|---|
path:"name" | Path parameters, via Request.PathValue |
query:"name" | URL query parameters |
body:"name" | Request body: JSON, form-encoded or multipart, by Content-Type |
json:"name" | Request body; for tags shared with serialisation |
cookie:"name" | Request cookies |
header:"name" | Request headers, matched case-insensitively |
form:"name" | A form body's value when it has the key, otherwise the query's, as r.FormValue reads |
Precedence when a field carries several: path,
query, body, json,
cookie, header. Options are
,omitempty and ,required. See
Binding sources.