Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/go-chi/chi/llms.txt

Use this file to discover all available pages before exploring further.

The Routes interface exposes chi’s routing tree for inspection and testing without making an actual HTTP request. It is embedded in the Router interface, so every chi router automatically satisfies it. The docgen sub-package uses this interface to generate human-readable API documentation straight from a live router.

Routes Interface

chi.go
type Routes interface {
    Routes() []Route
    Middlewares() Middlewares
    Match(rctx *Context, method, path string) bool
    Find(rctx *Context, method, path string) string
}

Routes() []Route

mux.go
func (mx *Mux) Routes() []Route
Returns a snapshot of the entire routing tree as a flat slice of Route values. Each entry describes one registered pattern, the HTTP methods it handles, and — for mounted sub-routers — the sub-router itself.
[]Route
A traversable slice of all registered routes in the trie. The order reflects the internal trie walk.
walk_routes.go
r := chi.NewRouter()
r.Get("/users", listUsers)
r.Post("/users", createUser)
r.Get("/users/{id}", getUser)

for _, route := range r.Routes() {
    for method := range route.Handlers {
        fmt.Printf("%s %s\n", method, route.Pattern)
    }
}
// GET  /users
// POST /users
// GET  /users/{id}
Walk sub-routers recursively by checking whether route.SubRoutes is non-nil and calling .Routes() on it again.
walk_routes_recursive.go
func walkRoutes(routes chi.Routes, depth int) {
    indent := strings.Repeat("  ", depth)
    for _, route := range routes.Routes() {
        for method := range route.Handlers {
            fmt.Printf("%s%s %s\n", indent, method, route.Pattern)
        }
        if route.SubRoutes != nil {
            walkRoutes(route.SubRoutes, depth+1)
        }
    }
}

Middlewares() Middlewares

mux.go
func (mx *Mux) Middlewares() Middlewares
Returns the slice of middleware handler functions registered on this router via Use(). For inline sub-routers this reflects only the middlewares added at that scope level.
Middlewares
The ordered slice of middleware functions; may be empty but never nil.
inspect.go
mws := r.Middlewares()
fmt.Printf("router has %d middleware(s)\n", len(mws))

Match

chi.go / mux.go
func (mx *Mux) Match(rctx *Context, method, path string) bool
Searches the routing tree for a handler that matches the given method and path, populating rctx with URL parameters and matched patterns — exactly like a real request, but without executing the handler.
rctx
*Context
required
A routing context to receive match results (URL params, route patterns). Create a fresh one with chi.NewRouteContext() to avoid state pollution.
method
string
required
The HTTP method to match, e.g. "GET".
path
string
required
The URL path to test, e.g. "/users/42".
bool
true when a matching handler was found; false otherwise.
The *Context is mutated during the search. Always pass a freshly allocated context from chi.NewRouteContext() or call rctx.Reset() between calls to avoid leaking state from a previous match.
router_test.go
func TestRouteMatch(t *testing.T) {
    r := chi.NewRouter()
    r.Get("/users/{id}", getUser)

    rctx := chi.NewRouteContext()
    if !r.Match(rctx, "GET", "/users/99") {
        t.Fatal("expected match")
    }
    t.Log("matched:", chi.URLParamFromCtx(rctx, "id")) // "99"
}

Find

chi.go / mux.go
func (mx *Mux) Find(rctx *Context, method, path string) string
Searches the routing tree and returns the matched route pattern string rather than a boolean. Like Match, it populates rctx without executing any handler. Returns an empty string when nothing matches.
rctx
*Context
required
A routing context to receive match state.
method
string
required
The HTTP method to search for.
path
string
required
The URL path to search for.
string
The matched route pattern, e.g. "/users/{id}", or "" if no match.
router_test.go
rctx := chi.NewRouteContext()
pattern := r.Find(rctx, "DELETE", "/articles/7")
fmt.Println(pattern) // "/articles/{id}"

Route Struct

Each element of the []Route slice returned by Routes() has the following shape:
tree.go
type Route struct {
    SubRoutes Routes
    Handlers  map[string]http.Handler
    Pattern   string
}
Pattern
string
The full URL pattern for this route node, e.g. "/users/{id}".
Handlers
map[string]http.Handler
A map from HTTP method strings (e.g. "GET", "POST") to their registered http.Handler. The key "*" represents a catch-all for any method.
SubRoutes
Routes
Non-nil for routes created via Mount or Route. Contains the mounted sub-router, allowing recursive traversal of the entire routing tree.

Middlewares Type

chi.go
type Middlewares []func(http.Handler) http.Handler
Middlewares is a named slice type for standard middleware functions. Beyond acting as a plain slice, it carries the Handler and HandlerFunc methods from chain.go that let you compose a full http.Handler from the stack without attaching the chain to a router.

Chain — Composing Middleware Outside a Router

Chain and the Middlewares methods in chain.go allow you to build a reusable middleware stack that can be applied to individual handlers without going through a Mux.

Chain

chain.go
func Chain(middlewares ...func(http.Handler) http.Handler) Middlewares
Wraps the provided middleware functions in the Middlewares type and returns them, enabling the .Handler and .HandlerFunc methods.
middlewares
...func(http.Handler) http.Handler
required
The ordered middleware functions to include in the chain. Executed left-to-right.
Middlewares
A Middlewares slice ready to have a final handler attached.
chain_example.go
stack := chi.Chain(
    middleware.Logger,
    middleware.Recoverer,
    requireAuth,
)

http.Handle("/secure", stack.HandlerFunc(secureHandler))

Middlewares.Handler

chain.go
func (mws Middlewares) Handler(h http.Handler) http.Handler
Builds and returns a *ChainHandler by wrapping h with the full middleware stack. Middlewares execute in the order they were passed to Chain.
h
http.Handler
required
The final endpoint handler to wrap.
http.Handler
A *ChainHandler that, when served, runs the entire middleware chain before calling h.
chain_example.go
composed := chi.Chain(
    middleware.RealIP,
    middleware.Logger,
).Handler(myHandler)

http.ListenAndServe(":8080", composed)

Middlewares.HandlerFunc

chain.go
func (mws Middlewares) HandlerFunc(h http.HandlerFunc) http.Handler
Identical to Handler but accepts a http.HandlerFunc for convenience.
h
http.HandlerFunc
required
The final endpoint handler function to wrap.
http.Handler
A *ChainHandler wrapping the provided function with the middleware stack.
chain_example.go
composed := chi.Chain(middleware.Logger).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("ok"))
})

ChainHandler

Chain/Handler/HandlerFunc all produce a *ChainHandler:
chain.go
type ChainHandler struct {
    Endpoint    http.Handler
    chain       http.Handler
    Middlewares Middlewares
}
Endpoint
http.Handler
The unwrapped final handler, accessible for inspection or testing without running the middleware stack.
Middlewares
Middlewares
The middleware functions in use by this chain, in execution order.
ChainHandler itself satisfies http.Handler via ServeHTTP, which delegates to the private chain field (the fully composed handler).

WalkFunc

tree.go
type WalkFunc func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error
WalkFunc is the callback type passed to Walk. It is called once per unique method-and-route combination in the router tree, including routes inside mounted sub-routers. Returning a non-nil error from the callback stops the walk and causes Walk to return that error.
method
string
The HTTP method for this route entry, e.g. "GET" or "POST".
route
string
The full route pattern from the root, e.g. "/api/v1/users/{id}".
handler
http.Handler
The registered endpoint handler (after the middleware chain is stripped).
middlewares
...func(http.Handler) http.Handler
All middleware functions that apply to this route, aggregated from the root through all sub-routers.

Walk

tree.go
func Walk(r Routes, walkFn WalkFunc) error
Walks the entire routing tree rooted at r, calling walkFn for every registered method-and-route pair. Sub-routers mounted via Mount or Route are traversed recursively. This is the primary mechanism for route introspection and API documentation generation.
r
Routes
required
The router to walk. Any value that satisfies the Routes interface — typically a *Mux.
walkFn
WalkFunc
required
The callback to invoke for each method-and-route pair.
error
The first non-nil error returned by walkFn, or nil if the walk completes without error.
walk_example.go
package main

import (
    "fmt"
    "net/http"

    "github.com/go-chi/chi/v5"
)

func main() {
    r := chi.NewRouter()
    r.Get("/", indexHandler)
    r.Route("/api/v1", func(r chi.Router) {
        r.Get("/users", listUsers)
        r.Post("/users", createUser)
        r.Get("/users/{id}", getUser)
    })

    // Walk the full router tree and print every route
    chi.Walk(r, func(method, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
        fmt.Printf("%-7s %s\n", method, route)
        return nil
    })

    http.ListenAndServe(":3000", r)
}
// Output:
// GET     /
// GET     /api/v1/users
// POST    /api/v1/users
// GET     /api/v1/users/{id}
The docgen package at github.com/go-chi/chi/v5/docgen provides production-ready helpers that walk the Routes tree and emit Markdown, JSON, or other formats. It relies entirely on the Routes interface and Walk — no reflection or code generation required.

Example: Manual Route Traversal

For cases where you need direct access to the Route struct (e.g. to inspect sub-routers or handlers individually), iterate Routes() recursively:
traverse_example.go
func printRoutes(routes chi.Routes, prefix string) {
    for _, route := range routes.Routes() {
        for method := range route.Handlers {
            if method == "*" {
                continue
            }
            fmt.Printf("%-7s %s%s\n", method, prefix, route.Pattern)
        }
        if route.SubRoutes != nil {
            trimmed := strings.TrimSuffix(route.Pattern, "/*")
            printRoutes(route.SubRoutes, prefix+trimmed)
        }
    }
}

Build docs developers (and LLMs) love