Documentation
binder maps the parts of an *http.Request onto the fields of a
struct, using struct tags to say where each field comes from. That is the
whole library. It does not validate, route, log or transform — those belong
to packages that already do them well.
These pages document v1.1.0. The module path is
uradical.io/go/binder and it requires Go 1.27.
The shape of it
One call, one struct. Each field names a source and a key; binder reads the request once, converts each value to the field's type, and reports the first field that could not be filled.
type UpdateUser struct {
ID int `path:"id"`
Fields []string `query:"fields"`
Name string `body:"name,required"`
Email string `body:"email,omitempty"`
Token string `cookie:"session"`
TraceID string `header:"X-Request-ID"`
}
func handler(w http.ResponseWriter, r *http.Request) {
var req UpdateUser
if err := binder.Bind(r, &req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// req is populated; every field came from where its tag says.
}Start here
1Install & quick start
Add the module and bind your first handler, in about five minutes.
2Binding sources
The six tags, what each reads, and which one wins when a field carries several.
3Types & conversion
Which Go types bind, how slices fill, and how to bind a type of your own.
4Error handling
Telling a bad request from a bad handler, and the status code for each.
What binder does not do
Knowing the edges early saves an afternoon of looking for a feature that was never there:
- No streamed uploads. A
multipart/form-databody binds its file parts, but the whole request is held in memory underMaxBodySizerather than spilled to disk. - No validation rules. There is a
Validatorhook so your own checks run as part of binding, but nomin,maxoremailtags. - No fixed-size arrays.
[]intbinds;[5]intdoes not. REST payloads are variable-length. - No defaults. A missing optional value leaves the field at its zero value; set defaults before you bind.
- No routing.
path:reads whatnet/http's ownPathValuealready resolved.
The README in the repository
is the canonical documentation and these pages track it. Where they
disagree, the source wins — and please
open an issue.