Stage 3 · Build
HTTP & REST APIs
Routing with chi and Gin
Compare chi routers and Gin engines for path parameters, route groups, and middleware chains.
Why Third-Party Routers?
Go 1.22 ServeMux handles basic routing well, but production APIs often need middleware per route group, automatic request validation, path parameter extraction in subrouters, and performance under high route counts. chi and Gin are the two most popular choices.
chi Router
chi is a lightweight, idiomatic Go router. It implements net/http Handler, so any middleware or handler that works with net/http works with chi. It supports route groups, URL parameters, and composable middleware.
Use chi.URLParam(r, "userID") to get the value of {userID} from the URL. This works anywhere in the handler chain, not just at the route level.
Gin Engine
Gin is a high-performance HTTP framework with a richer feature set. It provides built-in validation, JSON binding, renderers, and a tree-based router. Gin does not implement net/http Handler directly, but provides an adapter.
Route Groups
Route groups let you share prefixes and middleware across related endpoints. This keeps your router clean and avoids repeating middleware configuration on every route.
| Feature | chi | Gin |
|---|---|---|
| Route groups | r.Route("/path", func(r chi.Router) {...}) | r.Group("/path") |
| Middleware per group | r.Use(handler) | group.Use(handler) |
| Nested groups | Yes, full nesting | Yes, full nesting |
| Path parameters | {userID} | :userID |
| Catch-all routes | {rest:*} | *action |
Middleware Chains
Both chi and Gin execute middleware in order. The first middleware registered runs first for incoming requests and last for responses. This onion-layer model lets you add logging, auth, and recovery in a predictable stack.
chi vs Gin
| Criteria | chi | Gin |
|---|---|---|
| Philosophy | Minimal, stdlib compatible | Full-featured framework |
| net/http compatible | Yes, directly | No, needs adapter |
| Performance | Fast, tree-based | Fastest benchmark |
| Built-in validation | No | Yes, with binding tags |
| JSON binding | Manual json.Decode | Automatic with c.ShouldBind |
| Community | Growing, stdlib-focused | Very large, mature |
Choose chi if you want stdlib compatibility, minimal abstractions, and full control. Choose Gin if you want batteries-included features like binding, validation, and rendering. Both are production-ready.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.