Project 2023 – 2026
go-router
A small, dependency-free HTTP router for Go on a compressed patricia trie, with lock-free lookups and a concurrency story verified under load rather than asserted.
- 0
- runtime dependencies
- lock-free
- route lookups
- 3 layers
- fuzz, benchmarks, load tests
What it is
A router in the spirit of chi: static routes and {param}
captures, groups, mounting and middleware chains, on top of the standard library only. It
started in 2023 as a way to learn how routers actually match paths, and grew into something I
would be comfortable depending on.
r := router.NewRouter()
r.Get("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("user " + context.Param(r, "id")))
})
r.Group("/admin", func(r *router.Router) {
r.Use(requireAuth)
r.Get("/stats", stats)
})
http.ListenAndServe(":3333", r)
Design
- Patricia trie matching. A shared literal prefix, even across a
/, collapses into one edge instead of one node per segment. The tree splits only at the byte where two routes first diverge. - Atomic tree swaps. Registration builds a new tree and swaps it in atomically, so adding or mounting routes while serving traffic never exposes a half-built tree, and lookups never take a lock.
- HTTP semantics done properly.
HEADfalls back toGET;OPTIONSon a known path answers204with a computedAllowheader. Registering either explicitly always wins. - Groups and mounting.
Groupshares a prefix and middleware;Mountgrafts another router’s routes, handlers and middleware intact, under a prefix.
Verification
Beyond unit tests, the routing tree carries three layers:
- Fuzz tests for route registration and lookup against arbitrary input.
- Benchmarks for static, parameter, escaped and miss lookups, including parallel and large-fanout cases.
- Load tests driven by vegeta that check correctness under concurrent load, including registering and mounting routes while traffic is in flight.
The last one is the point: “concurrency-safe” is a claim, and the load test is what makes it a fact.