Day 087 — Routing with chi¶
Month 4 · Week 1 · ⬅ Day 086 · Day 088 ➡ · Journal index
🎯 Learning Objective¶
Use github.com/go-chi/chi/v5 for ergonomic routing — URL params, sub-routers,
route groups — and know when it earns its keep over the stdlib mux.
📚 Topics¶
chi.NewRouter,r.Get/Post/...,chi.URLParam,r.Route,r.Mountr.Group, route-scoped middleware, 100%net/http-compatible handlers
📖 Reading / Sources¶
📝 Notes¶
- chi is a thin, stdlib-compatible router: every handler is a normal
http.Handler/HandlerFunc, andchi.Routeris anhttp.Handler. No framework lock-in → swappable with [[http-handler]]. - Read params with
chi.URLParam(r, "id")(chi stores them on the request context). Patterns use{name}and regex constraints like{id:[0-9]+}. - Sub-routers keep large APIs tidy:
r.Route("/users", func(r chi.Router){...})scopes a path prefix;r.Mount("/admin", adminRouter)grafts a whole router. r.Groupapplies middleware to a set of routes without changing their path prefix — handy for "these endpoints need auth".- chi ships a battle-tested
middlewarepackage (RequestID, RealIP, Logger, Recoverer, Timeout) — samefunc(http.Handler) http.Handlershape as Day 088. - When to choose it: since Go 1.22 the stdlib mux covers method + wildcard routing, so reach for chi when you want nested routers, route groups, regex params, or the ready-made middleware stack. For a few endpoints, stdlib is enough → [[router-choice]].
- This needs a third-party module, so today has no runnable example in the repo; the snippet below is the reference.
💻 Code Examples¶
// go get github.com/go-chi/chi/v5
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main() {
r := chi.NewRouter()
r.Use(middleware.RequestID, middleware.Logger, middleware.Recoverer)
r.Route("/users", func(r chi.Router) {
r.Get("/", listUsers) // GET /users
r.Post("/", createUser) // POST /users
r.Route("/{id:[0-9]+}", func(r chi.Router) {
r.Get("/", getUser) // GET /users/{id}
r.Delete("/", deleteUser) // DELETE /users/{id}
})
})
// Auth only for this group; same path prefix as siblings.
r.Group(func(r chi.Router) {
r.Use(requireAuth)
r.Get("/me", whoAmI)
})
http.ListenAndServe(":8087", r) // chi.Router is an http.Handler
}
func getUser(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id") // chi reads params from the request context
_ = id
}
🏋️ Exercises / Practice¶
| Exercise | Status | Link |
|---|---|---|
| Re-create method routing on the stdlib mux (chi-free) | ✅ | exercises/month-04/week-1/pathrouter |
🐛 Mistakes Made¶
- Reached for
r.PathValueinside a chi handler — that's the stdlib mux API; with chi you callchi.URLParam(r, "id"). - Put a
/{id}route before more specific literal routes and worried about order; chi matches by specificity, but being explicit avoided surprises.
❓ Open Questions¶
- How does chi's trie matcher compare in latency to the stdlib mux at scale? (Both are O(path length)-ish; benchmark before assuming.)
🧠 Active Recall (answer without looking)¶
- Q: How do you read a URL parameter in a chi handler?
A
`chi.URLParam(r, "id")` — chi stores matched params on the request context.- Q: Difference between
r.Routeandr.Groupin chi?
A
`Route` scopes a **path prefix** (a sub-router); `Group` scopes **middleware** to a set of routes **without** adding a path prefix.🪶 Feynman Reflection¶
chi is the stdlib mux with nicer ergonomics: nested routers, regex params, and
groups for shared middleware, while every handler stays a plain net/http
handler so nothing is locked in. Since Go 1.22 I only graduate to it when the
routing tree gets genuinely nested.
🕳️ Knowledge Gaps¶
- chi's
NotFound/MethodNotAllowedcustomisation and how it differs from the stdlib mux's automatic 405.
✅ Summary¶
I can structure a real API with chi — sub-routers, regex params, and grouped middleware — and I know when the stdlib mux is already enough.
⏭️ Next Steps / Prep for Tomorrow¶
- Day 088: middleware chains — the
func(http.Handler) http.Handlerpattern.
| Time spent | Difficulty | Confidence |
|---|---|---|
| 90 min | 🟦🟦⬜⬜⬜ | 🟦🟦🟦⬜⬜ |
Suggested commit: docs(journal): routing with chi sub-routers and groups (day 087)