Documentation
¶
Overview ¶
Package gorilla is a router plugin for github.com/gorilla/mux. It statically recognizes route registrations on a *mux.Router:
r.HandleFunc("/users/{id}", GetUser).Methods("GET") // method(s) via a chained .Methods()
r.Handle("/users", http.HandlerFunc(CreateUser)).Methods("POST")
r.HandleFunc("/health", HealthCheck) // no .Methods() -> every HTTP method
s := r.PathPrefix("/api/v1").Subrouter() // a subrouter variable carries a path prefix,
s.HandleFunc("/users", ListUsers) // accumulated across nested subrouters -> "/api/v1/users"
It does not import the real mux: recognition is pure go/types path/name matching against the analyzed target's own type-checked packages, the same mechanism internal/router/nethttp uses for *http.ServeMux — gota's own build never depends on gorilla/mux.
mux handlers are plain func(w http.ResponseWriter, r *http.Request) using ordinary encoding/json — gorilla introduces no response-writing idiom of its own — so this plugin pairs with the existing inference.NetHTTP() dialect unchanged.
Methods ¶
A route's HTTP methods come from a .Methods("GET", ...) call chained onto the *mux.Route that HandleFunc/Handle returns — anywhere in the builder chain (.Methods(...).Name(...), .Schemes(...).Methods(...)). A registration with no .Methods() at all matches every method (that is gorilla's own semantics), so it expands to one operation per HTTP method, the same as a method-less net/http ServeMux pattern. A .Methods() whose arguments aren't compile-time-constant strings is declined (the route's methods are unknowable) rather than guessed.
Middleware indirection ¶
The handler passed to Handle/HandleFunc is frequently the real handler wrapped in middleware — the point of indirection body inference has to see through. resolveHandler unwraps it type-aware: it follows the one argument of each wrapping call whose type is http.Handler-shaped (http.Handler, http.HandlerFunc, or func(http.ResponseWriter, *http.Request)), down to the real handler. This covers a single-arg wrapper (http.HandlerFunc(H), authMiddleware(H)), a multi-argument middleware whose other arguments aren't handlers (gorilla's own handlers.LoggingHandler(os.Stdout, H)), and a curried one (handlers.CORS(opts)(H)). It stops where no single handler-shaped argument identifies the next hop (zero, or two-or-more). Router-level middleware (r.Use(mw)) doesn't wrap a specific handler and is correctly irrelevant to inference.
The handler is also commonly produced by a factory call returning http.Handler — a free function (Handle(p, made())) or a method (Handle(p, controller.build())), the idiom of returning a handler already wrapped in middleware. The route is recognized via the factory's own name (its operationId), and the factory's body is where body inference then looks.
A subrouter built with NewRoute().Subrouter() (a middleware-only subrouter, "sec := root.NewRoute().Subrouter()") adds no path segment but INHERITS the parent's accumulated prefix, so routes on it keep the parent's path.
Path parameters ¶
mux templates use "{name}" (already OpenAPI's syntax) and "{name:regex}" constraints, which degrade to the bare "{name}" (no direct OpenAPI equivalent) — including a "{rest:.*}" catch-all, which becomes "{rest}".
Mounts ¶
A sub-router mounted on another router has the mount's path prefix applied to its own routes, for a same-package constructor (a zero-arg func returning *mux.Router), via either idiom:
root.Handle("/v2", ctor()) // and mux's
root.Handle("/v2/{rest:.*}", ctor()) // subpath idiom (deduped)
root.PathPrefix("/v2").Handler(http.StripPrefix("/v2", ctor()))
The constructor is walked once per distinct mount prefix (collectMounts) and NOT standalone, so its routes appear under the prefix they're mounted at, not unprefixed. A Handle whose handler is a *mux.Router that ISN'T a followable constructor (a plain variable, whose routes are already extracted where they're registered) is declined as an endpoint rather than emitted as a catch-all that would duplicate them. Mounting a constructor declared in a DIFFERENT package is the cross-package mount gap — the constructor body is invisible to a single-package Extract, so those routes surface at the prefix they carry themselves, the same boundary as chi's cross-package Mount.
Known, deliberate v1 gaps (declined, not guessed):
- The builder form that splits the path and handler across the chain (r.Path("/x").HandlerFunc(H), r.Methods("GET").Path("/x").Handler(h)): this plugin anchors on HandleFunc/Handle, which carry both the path and the handler in one call.
- A subrouter variable assigned more than once (ambiguous prefix), a non-constant PathPrefix/Path template, and a subrouter whose receiver chain can't be resolved to a constant prefix.
- A non-constant registration path or a non-constant .Methods() argument.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.