Zero-allocation matching
Matching, middleware chains and finding no route allocate nothing. On fasthttp, neither do params or mounts.
Route net/http and fasthttp requests to plain handlers. Matching allocates nothing, params use the standard r.PathValue, and middleware costs nothing per request.
go get github.com/vardius/gorouter/v5 func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "hello, %s!\n", r.PathValue("name"))}
func main() { router := gorouter.New() router.GET("/hello/{name}", hello) log.Fatal(http.ListenAndServe(":8080", router))}func hello(ctx *fasthttp.RequestCtx) { fmt.Fprintf(ctx, "hello, %s!\n", fastrouter.Param(ctx, "name"))}
func main() { router := fastrouter.New() router.GET("/hello/{name}", hello) log.Fatal(fasthttp.ListenAndServe(":8080", router.HandleFastHTTP))}Features
Zero-allocation matching
Matching, middleware chains and finding no route allocate nothing. On fasthttp, neither do params or mounts.
Standard handlers
Any http.Handler, the usual func(http.Handler) http.Handler middleware, and params read with
the standard r.PathValue.
Params and regexps
{id} matches a segment, {id:[0-9]+} only one the regexp matches. Literals win, and a failed
branch falls back to the next.
Scoped middleware
Around the whole router, the routes below a path, or one method below a path. Composed once at registration.
Mounting
Hand a path to a sub-router or a file server. It sees paths relative to the mount, and mount params stay readable.
Correct by default
405 with an Allow header, automatic OPTIONS, custom methods, and clear panics for invalid
patterns.
Performance
v5 composes middleware once at registration instead of on every request, and matches without allocating. A route behind three middleware went from 170 ns to 24 ns on net/http.
| Scenario | v4 | v5 |
|---|---|---|
| Static route | 20.0 ns0 allocs | 19.9 ns0 allocs |
| Static, 5 segments | 28.5 ns0 allocs | 30.2 ns0 allocs |
| One param | 87.0 ns4 allocs | 93.6 ns2 allocs |
| Three params + regexp | 150.1 ns4 allocs | 148.5 ns2 allocs |
| Static + 3 middleware | 170.4 ns6 allocs | 23.8 ns0 allocs |
| One param + 3 middleware | 238.4 ns10 allocs | 100.8 ns2 allocs |
| 404 Not Found | 20.0 ns0 allocs | 20.3 ns0 allocs |
| 405 Method Not Allowed | 60.8 ns3 allocs | 55.8 ns2 allocs |
Apple M4 Max, Go 1.27.0, median of 5 runs.
| Scenario | v4 | v5 |
|---|---|---|
| Static route | 30.0 ns1 alloc | 16.9 ns0 allocs |
| Static, 5 segments | 39.0 ns1 alloc | 26.2 ns0 allocs |
| One param | 50.1 ns3 allocs | 38.5 ns0 allocs |
| Three params + regexp | 110.2 ns3 allocs | 87.4 ns0 allocs |
| Static + 3 middleware | 173.1 ns7 allocs | 18.3 ns0 allocs |
| One param + 3 middleware | 192.8 ns9 allocs | 39.5 ns0 allocs |
| 404 Not Found | 29.7 ns1 alloc | 15.3 ns0 allocs |
| 405 Method Not Allowed | 89.0 ns3 allocs | 69.5 ns1 alloc |
Apple M4 Max, Go 1.27.0, median of 5 runs.
Upgrading
The patterns stay the same. The API around them is smaller: options instead of setters, the standard
r.PathValue instead of a params type, and a fastrouter package for fasthttp.
router := gorouter.New(logger)router.GET("/hello/{name}", http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { params, _ := context.Parameters(r.Context()) fmt.Fprintf(w, "hello, %s!", params.Value("name")) },))router.USE(http.MethodGet, "/admin", auth)router := gorouter.New(gorouter.WithMiddleware(logger))router.GET("/hello/{name}", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "hello, %s!", r.PathValue("name")) },)router.UseMethod(http.MethodGet, "/admin", auth)Install the module, register a handler, and serve. The guide walks through params, middleware and mounting.