binder / Docs / Install & quick start
Install & quick start
binder has no dependencies and no build step of its own. Adding it is one
go get; using it is one function.
Requirements
Go 1.27 or newer. binder's go.mod declares Go 1.27, so earlier toolchains will not build it. See the Go version policy for how that minimum moves.
Install
Fetches the latest release and records it in go.mod.
go get uradical.io/go/binderAsk for a particular release rather than whatever is newest.
go get uradical.io/go/binder@v1.2.0Write the import first and let the toolchain work out the rest.
go mod tidyEither way, import it as binder:
import "uradical.io/go/binder"Your first handler
A route with a path parameter, an optional query flag and a JSON body — three sources, one struct, one call.
package main
import (
"encoding/json"
"log"
"net/http"
"uradical.io/go/binder"
)
type CreateComment struct {
PostID int `path:"id"`
Notify bool `query:"notify"`
Author string `body:"author,required"`
Text string `body:"text,required"`
Tags []string `body:"tags,omitempty"`
}
func createComment(w http.ResponseWriter, r *http.Request) {
var req CreateComment
if err := binder.Bind(r, &req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
json.NewEncoder(w).Encode(req)
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("POST /posts/{id}/comments", createComment)
log.Fatal(http.ListenAndServe(":8080", mux))
}Run it, then send a request that exercises all three sources:
curl -X POST 'http://localhost:8080/posts/42/comments?notify=true' \
-H 'Content-Type: application/json' \
-d '{"author":"ada","text":"first","tags":["intro","meta"]}'{"PostID":42,"Notify":true,"Author":"ada","Text":"first","Tags":["intro","meta"]}
Now drop the author key and send it again. Because that field
is tagged required, binding fails and the handler answers
400 with a message naming the field and the source it should have come
from. Drop text as well, and both are reported, one per
line:
missing required field Author: no body value named "author"
missing required field Text: no body value named "text"
ErrMissingRequired rather than on the string, and use
BindErrors to answer field by field. See
Error handling.
What the body needs to say
Body binding follows the request's Content-Type. Send
application/json for JSON,
application/x-www-form-urlencoded for a form, or
multipart/form-data for a form with files; anything else
leaves the body unparsed and the request binds from its path, query,
cookie and header values alone (the body is still read, within the size
limit, when a field binds from it). The same struct handles both, so an HTML
form post and an API call can share a handler:
curl -X POST 'http://localhost:8080/posts/42/comments' \
-d 'author=ada&text=first&tags=intro&tags=meta'Where to go next
- Binding sources — the seven tags and their precedence.
- Options —
required,omitemptyand per-call configuration. - Error handling — turning a bind failure into the right status code.