GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - vardius/gorouter: Go Server/API micro framework, HTTP request router, multiplexer, mux

BranchesTags
Open more actions menu

Latest commit

 

History

529 Commits
529 Commits

Folders and files

NameName
Last commit message
Last commit date
.github
.github
 
 
examples
examples
 
 
fastrouter
fastrouter
 
 
internal
internal
 
 
website
website
 
 
.gitignore
.gitignore
 
 
CHANGELOG.md
CHANGELOG.md
 
 
LICENSE.md
LICENSE.md
 
 
MIGRATION.md
MIGRATION.md
 
 
README.md
README.md
 
 
alloc_test.go
alloc_test.go
 
 
benchmark_test.go
benchmark_test.go
 
 
doc.go
doc.go
 
 
example_test.go
example_test.go
 
 
go.mod
go.mod
 
 
go.sum
go.sum
 
 
router.go
router.go
 
 
router_test.go
router_test.go
 
 

Repository files navigation

🍃 gorouter

Test Go Reference Go Report Card License: MIT

A fast HTTP router for Go, for both net/http and fasthttp.

  • Zero-allocation routing. Matching a route, running its middleware and finding no route allocate nothing; on fasthttp, neither do params or mounts.
  • Standard handlers. Plain http.Handlers and func(http.Handler) http.Handler middleware; read params with the standard r.PathValue.
  • Params and regexps. /users/{id}, /users/{id:[0-9]+}, with literals winning over params and backtracking when a branch fails further down.
  • Scoped middleware. Around the whole router, the routes below a path, or one method below a path. Composed once at registration, never per request.
  • Mounting. Hand a path to a sub-router or a file server, with the prefix stripped.
  • Correct by default. 405 with an Allow header, automatic OPTIONS, custom methods.

📖 Documentation · API reference · Examples · Migrating from v4

Install

go get github.com/vardius/gorouter/v5

Requires Go 1.26 or newer.

Quick start

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/vardius/gorouter/v5"
)

func main() {
	r := gorouter.New()
	r.GET("/", func(w http.ResponseWriter, _ *http.Request) {
		fmt.Fprintln(w, "welcome")
	})
	r.GET("/hello/{name}", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "hello, %s!\n", r.PathValue("name"))
	})

	log.Fatal(http.ListenAndServe(":8080", r))
}

The same with fasthttp, from the fastrouter package, so net/http users never link fasthttp:

r := fastrouter.New()
r.GET("/hello/{name}", func(ctx *fasthttp.RequestCtx) {
	fmt.Fprintf(ctx, "hello, %s!\n", fastrouter.Param(ctx, "name"))
})

log.Fatal(fasthttp.ListenAndServe(":8080", r.HandleFastHTTP))

Routing

r.GET("/users/new", newUser)              // literal
r.GET("/users/{id:[0-9]+}", userByID)     // regexp param: the whole segment must match
r.GET("/users/{name}", userByName)        // param: any one segment
r.GET("/users/{name}/posts", postsByUser) // /users/new/posts lands here
r.Handle("PURGE", "/cache/{key}", purge)  // any method, any http.Handler

Literals win over regexp params, regexp params are tried in registration order, and a plain param comes last. If the preferred branch fails further down the path, the router backtracks to the next one. A trailing slash is ignored and an empty segment never matches.

Middleware

r := gorouter.New(gorouter.WithMiddleware(logRequests, recoverPanics)) // whole router, 404 and 405 included
r.Use("/admin", basicAuth)                                            // every route below /admin
r.UseMethod(http.MethodPost, "/api", requireJSON)                     // POST routes below /api

Middleware runs in registration order, outermost first, and covers routes registered before and after the call. Use picks routes by pattern, not by request path: a request runs the middleware of the route it matches, so /admin/users matched by /{section}/users doesn't run basicAuth.

Mounting

r.Mount("/api/v1", v1Router)                          // v1Router sees /users/7 for /api/v1/users/7
r.Mount("/orgs/{org}", orgRouter)                     // r.PathValue("org") still works inside
r.Mount("/static", http.FileServerFS(os.DirFS("public")))

A mount takes every method, custom ones included. Middleware on the mount path or above wraps it; middleware for paths below it belongs in the mounted router, and Use panics if asked to put it there.

Benchmarks

Time and allocations to route one request, on an Apple M4 Max with Go 1.27.0, median of 5 runs. Both versions ran on the same harness, with no-op handlers and middleware. Run v5's own suite with go test -bench . ./....

Scenario net/http v4 net/http v5 fasthttp v4 fasthttp v5
Static route 20.0 ns · 0 allocs 19.9 ns · 0 allocs 30.0 ns · 1 alloc 16.9 ns · 0 allocs
Static, 5 segments 28.5 ns · 0 allocs 30.2 ns · 0 allocs 39.0 ns · 1 alloc 26.2 ns · 0 allocs
One param 87.0 ns · 4 allocs 93.6 ns · 2 allocs 50.1 ns · 3 allocs 38.5 ns · 0 allocs
Three params + regexp 150.1 ns · 4 allocs 148.5 ns · 2 allocs 110.2 ns · 3 allocs 87.4 ns · 0 allocs
Static + 3 middleware 170.4 ns · 6 allocs 23.8 ns · 0 allocs 173.1 ns · 7 allocs 18.3 ns · 0 allocs
One param + 3 middleware 238.4 ns · 10 allocs 100.8 ns · 2 allocs 192.8 ns · 9 allocs 39.5 ns · 0 allocs
404 20.0 ns · 0 allocs 20.3 ns · 0 allocs 29.7 ns · 1 alloc 15.3 ns · 0 allocs
405 60.8 ns · 3 allocs 55.8 ns · 2 allocs 89.0 ns · 3 allocs 69.5 ns · 1 alloc

On net/http, the two allocations for params are the ones Request.SetPathValue makes to store them for r.PathValue; matching itself allocates nothing. Storing them that way also makes a one-param route a few nanoseconds slower than v4, the price of reading params with the standard r.PathValue. A 405 allocates its Allow header value, and a mount one copy of the request, as http.StripPrefix does.

Across a 70-route, GitHub-style API (BenchmarkAPI), an average request takes 95.5 ns on net/http and 53.1 ns with zero allocations on fasthttp.

Upgrading from v4

v5 is a new major version with a smaller API. The short version:

// v4
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)

// v5
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)

MIGRATION.md maps every v4 call to its v5 form and lists the behaviour changes.

Contributing

Bug reports and pull requests are welcome: see CONTRIBUTING.md. For a ready-made API layout built on gorouter, see go-api-boilerplate.

License

MIT, see LICENSE.md.

About

Go Server/API micro framework, HTTP request router, multiplexer, mux

vardius.github.io/gorouter/

Topics

frameworkgoroutergoserverhttp-servermultiplexermuxno-showcaseroutershowcase

Resources

Readme
MIT license

Code of conduct

Code of conduct

Contributing

Contributing
Activity

Stars

153 stars

Watchers

7 watching

Forks

17 forks
Report repository

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.