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 reads path parameters through Request.PathValue and uses the standard library's uuid package, 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/binder

Ask for a particular release rather than whatever is newest.

go get uradical.io/go/binder@v1.1.0

Write the import first and let the toolchain work out the rest.

go mod tidy

Either 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"]}'
response
{"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, nothing is bound and the handler answers 400 with a message naming the field and the source it should have come from:

response
missing required field Author: no body value named "author"
The error text is deliberately not part of the API — match on ErrMissingRequired rather than on the string. See Error handling.

What the body needs to say

Body binding follows the request's Content-Type. Send application/json for JSON or application/x-www-form-urlencoded for a form; anything else leaves the body unparsed and the request binds from its path, query, cookie and header values alone. 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