Documentation
¶
Overview ¶
Package router is a router for websites and APIs on top of the ServeMux of net/http and its method-aware patterns. It adds route groups, middleware for routes and for every request, host and subdomain routing, named routes with reverse routing, mounted routers, not found pages, route matching and OpenAPI helpers. Routes are registered at startup: registration freezes on the first request. See https://docs.gowebthings.com/go-router for the documentation.
Index ¶
- Constants
- Variables
- func BadRequest(w http.ResponseWriter, err error) error
- func BoolParam(r *http.Request, name string) (bool, error)
- func DecodeJSON(r *http.Request, v any) error
- func Error(w http.ResponseWriter, statusCode int, err error) error
- func Float64Param(r *http.Request, name string) (float64, error)
- func Int64Param(r *http.Request, name string) (int64, error)
- func IntParam(r *http.Request, name string) (int, error)
- func InternalServerError(w http.ResponseWriter, err error) error
- func JSON(w http.ResponseWriter, statusCode int, v any) error
- func LocalURL(target string) (*url.URL, bool)
- func MatchedLabel(req *http.Request, labels ...string) (label string, ok bool)
- func MessageError(message string) error
- func NoIntercept(w http.ResponseWriter)
- func Param(r *http.Request, name string) string
- type Components
- type DocIn
- type DocOut
- type Docs
- type Info
- type MediaType
- type Middleware
- type MountOption
- type OpenAPI
- type Operation
- type Option
- type Parameter
- type PathFunc
- type PathItem
- type RequestBody
- type Response
- type RouteError
- type RouteInfo
- type RouteRegistration
- func (rr *RouteRegistration) As(name string) *RouteRegistration
- func (rr *RouteRegistration) Label(labels ...string) *RouteRegistration
- func (rr *RouteRegistration) TryAs(name string) (err error)
- func (rr *RouteRegistration) TryLabel(labels ...string) (err error)
- func (rr *RouteRegistration) TryUse(middlewares ...Middleware) (err error)
- func (rr *RouteRegistration) Use(middlewares ...Middleware) *RouteRegistration
- type Router
- func (r *Router) AddServerEndpoint(url string, description string)
- func (r *Router) At(prefix string) *Router
- func (r *Router) Delete(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
- func (r *Router) For(req *http.Request) *Router
- func (r *Router) FuncMap() map[string]any
- func (r *Router) Get(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
- func (r *Router) Group(basePath string, fn func(*Router))
- func (r *Router) Handle(pattern string, handler http.Handler) *RouteRegistration
- func (r *Router) HandleFunc(pattern string, handler http.HandlerFunc) *RouteRegistration
- func (r *Router) HandleStatus(httpStatus int, handler http.HandlerFunc)
- func (r *Router) HasRoute(name string) bool
- func (r *Router) Head(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
- func (r *Router) Host(hostPattern string, fn func(*Router))
- func (r *Router) IsActiveRoute(current any, name string, args ...any) (bool, error)
- func (r *Router) IsActiveRouteExact(current any, name string, args ...any) (bool, error)
- func (r *Router) Match(method string, path string) (RouteInfo, bool)
- func (r *Router) MatchLabel(method string, path string, labels ...string) (label string, ok bool)
- func (r *Router) MethodNotAllowed(handler http.Handler)
- func (r *Router) Mount(pattern string, handler http.Handler, options ...MountOption) *RouteRegistration
- func (r *Router) NotFound(handler http.Handler)
- func (r *Router) OpenAPI() *OpenAPI
- func (r *Router) OperationID(s string) string
- func (r *Router) Options(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
- func (r *Router) Owns(path string) (RouteInfo, bool)
- func (r *Router) OwnsLabel(path string, labels ...string) (label string, ok bool)
- func (r *Router) Patch(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
- func (r *Router) Post(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
- func (r *Router) Put(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
- func (r *Router) RedirectTrailingSlash(redirect bool)
- func (r *Router) RouteHost(name string) string
- func (r *Router) RoutePath(name string) string
- func (r *Router) RoutePathArgs(name string, args ...any) (string, error)
- func (r *Router) RoutePathWithParams(name string, params map[string]any) string
- func (r *Router) RouteTable() string
- func (r *Router) RouteURL(name string, params map[string]any, scheme string) string
- func (r *Router) Routes() map[string]RouteInfo
- func (r *Router) ServeAt(w http.ResponseWriter, req *http.Request, prefix string, ...)
- func (r *Router) ServeFile(pattern string, filepath string) *RouteRegistration
- func (r *Router) ServeFiles(pattern string, fs http.FileSystem) *RouteRegistration
- func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
- func (r *Router) Subdomain(subdomain string, domain string, fn func(*Router))
- func (r *Router) TrackRoutes()
- func (r *Router) TryDelete(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
- func (r *Router) TryGet(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
- func (r *Router) TryHandle(pattern string, handler http.Handler) (routeRegistration *RouteRegistration, err error)
- func (r *Router) TryHandleFunc(pattern string, handler http.HandlerFunc) (*RouteRegistration, error)
- func (r *Router) TryHead(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
- func (r *Router) TryMount(pattern string, handler http.Handler, options ...MountOption) (routeRegistration *RouteRegistration, err error)
- func (r *Router) TryOptions(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
- func (r *Router) TryPatch(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
- func (r *Router) TryPost(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
- func (r *Router) TryPut(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
- func (r *Router) Use(middleware Middleware)
- func (r *Router) UseAll(middlewares ...Middleware)
- func (r *Router) UseDocs(doc Docs)
- func (r *Router) UseOpenapiDocs(use bool)
- func (r *Router) Walk(fn WalkFunc) error
- func (r *Router) WildcardSubdomain(domain string, fn func(*Router))
- func (r *Router) With(fn func(*Router))
- func (r *Router) WriteRouteTable(w io.Writer) error
- type Schema
- type SecurityScheme
- type Server
- type Tag
- type WalkFunc
Constants ¶
const HeaderFlagDoNotIntercept = "do_not_intercept"
HeaderFlagDoNotIntercept is a response header that keeps a response from being replaced by a HandleStatus handler. The router removes it before the response is sent. NoIntercept does the same without a header.
Variables ¶
var ( // ErrUnknownRoute is returned for a route name that was never registered. ErrUnknownRoute = errors.New("unknown route") // ErrMissingParam is returned when a route parameter has no value. ErrMissingParam = errors.New("missing route parameter") // ErrUnknownParam is returned for a parameter the route does not have. ErrUnknownParam = errors.New("unknown route parameter") )
var ( DefaultRedirectTrailingSlash = false DefaultRedirectStatusCode = http.StatusTemporaryRedirect // or http.StatusMovedPermanently DefaultUseOpenapiDocs = false OpenApiVersion = "3.0.1" )
Functions ¶
func BadRequest ¶ added in v0.9.0
func BadRequest(w http.ResponseWriter, err error) error
func Float64Param ¶ added in v0.9.0
func InternalServerError ¶ added in v0.9.0
func InternalServerError(w http.ResponseWriter, err error) error
func LocalURL ¶ added in v0.12.0
LocalURL reports whether target, such as a ?next= or back value from a form, is a path on this site that can be redirected to without an open redirect: it starts with a single slash, has no scheme or host, and no backslash or line break, which browsers may read as another host. It returns the target parsed when it is, so its Path, RawQuery and EscapedPath can be read without parsing it again:
page, ok := router.LocalURL(req.FormValue("path"))
if !ok {
page = &url.URL{Path: "/"}
}
preview.Path, preview.RawQuery = page.Path, page.RawQuery
middleware.SameOriginReferer does the same for the Referer.
func MatchedLabel ¶ added in v0.12.0
MatchedLabel returns a label of the route that served req, as MatchedRoute reports it, without copying the route: the first of the route's labels that is one of labels, or its first label when no labels are given, and "" when it has none of them. ok is what MatchedRoute reports: false when no route served req. It is the cheap way to count requests by kind of route:
class, _ := router.MatchedLabel(req, "admin", "asset", "media")
if class == "" {
class = "public"
}
The labels of the mounts a route is below come before its own, as in RouteInfo.Labels.
func MessageError ¶ added in v0.9.0
func NoIntercept ¶ added in v0.12.0
func NoIntercept(w http.ResponseWriter)
NoIntercept keeps the response written to w from being replaced by the handlers of HandleStatus, for a handler that writes its own error page:
func page(w http.ResponseWriter, req *http.Request) {
if missing {
router.NoIntercept(w)
w.WriteHeader(http.StatusNotFound)
renderNotFound(w, req)
return
}
...
}
Call it before the status is written. It reaches the router through response writers that implement Unwrap() http.ResponseWriter, as the writers of this package's middleware and http.ResponseController-aware wrappers do, and applies to every router on the way, also routers a mounted router is mounted on. For a wrapper without Unwrap, set the HeaderFlagDoNotIntercept header instead. It does nothing when no status handlers are registered.
Types ¶
type Components ¶
type Components struct {
Schemas map[string]Schema `json:"schemas,omitempty"` // Reusable schemas
SecuritySchemes map[string]SecurityScheme `json:"securitySchemes,omitempty"` // Security schemes
}
Components holds reusable components such as schemas and security schemes.
type Docs ¶
type Docs struct {
Tags []string // Tags for the operation
Summary string // Short summary of the operation
Description string // Operation description
Parameters []Parameter // Parameters for the operation
RequestBody *RequestBody // Request body for the operation
Responses map[string]Response // Expected responses
Security []map[string][]string // Security requirements
In map[string]DocIn
Out map[string]DocOut
}
type Info ¶
type Info struct {
Title string `json:"title" validate:"required"` // API title
Description string `json:"description,omitempty"` // API description
Version string `json:"version" validate:"required"` // API version
}
Info represents the API metadata.
type MediaType ¶
type MediaType struct {
Schema *Schema `json:"schema,omitempty"` // Schema describing the type
}
MediaType represents the media type of a request or response body.
type MountOption ¶ added in v0.12.0
type MountOption func(*mountOptions)
MountOption configures Mount.
func AbsolutePaths ¶ added in v0.12.0
func AbsolutePaths() MountOption
AbsolutePaths mounts a router whose patterns include the mount path already, such as a router that registers its routes below a base path it was given:
admin := router.NewSite()
admin.Get("/admin/{$}", dashboard).As("admin.dashboard")
r.Mount("/admin", admin, router.AbsolutePaths())
Requests at and below the mount path reach the mounted router unchanged, and its routes, names and OpenAPI paths are taken over as they are, without the mount path in front. Routes of such a router outside the mount path are listed, but never reached. A handler that is not a router sees the full path as well, instead of the path below the mount.
func NamePrefix ¶ added in v0.12.0
func NamePrefix(prefix string) MountOption
NamePrefix puts prefix before the route names of a mounted router, as the router it is mounted on sees them, so a router can be mounted more than once, such as one per instance of a module:
r.Mount("/_/comments", comments, router.NamePrefix("comments."))
r.RoutePath("comments.post") // "/_/comments/post"
The mounted router resolves its own names with the prefix first, so comments.RoutePath("post") is "/_/comments/post" as well, and the names of the routers it is mounted on without it.
type OpenAPI ¶
type OpenAPI struct {
Openapi string `json:"openapi" validate:"required"` // OpenAPI version (e.g., "3.0.1")
Info Info `json:"info" validate:"required"` // API information
Servers []Server `json:"servers,omitempty"` // Server details
Paths map[string]PathItem `json:"paths" validate:"required"` // Paths and operations
Components Components `json:"components,omitempty"` // Components such as schemas and security schemes
Security []map[string][]string `json:"security,omitempty"` // Global security settings
Tags []Tag `json:"tags,omitempty"` // Tags for API organization
}
OpenAPI represents the root OpenAPI document.
type Operation ¶
type Operation struct {
Tags []string `json:"tags,omitempty"` // Tags for the operation
Summary string `json:"summary,omitempty"` // Short summary of the operation
Description string `json:"description,omitempty"` // Operation description
OperationID string `json:"operationId,omitempty"` // Unique operation ID
Parameters []Parameter `json:"parameters,omitempty"` // Parameters for the operation
RequestBody *RequestBody `json:"requestBody,omitempty"` // Request body for the operation
Responses map[string]Response `json:"responses" validate:"required"` // Expected responses
Security []map[string][]string `json:"security,omitempty"` // Security requirements
}
Operation describes a single API operation on a path.
type Option ¶ added in v0.12.0
type Option func(*Router)
Option configures a Router made by NewSite.
func WithMethodNotAllowed ¶ added in v0.12.0
WithMethodNotAllowed sets the router's MethodNotAllowed handler.
func WithNotFound ¶ added in v0.12.0
WithNotFound sets the router's NotFound handler.
type Parameter ¶
type Parameter struct {
Name string `json:"name" validate:"required"` // Parameter name
In string `json:"in" validate:"required"` // Location (e.g., "query", "header", "path")
Description string `json:"description,omitempty"` // Parameter description
Required bool `json:"required,omitempty"` // Is parameter required?
Schema *Schema `json:"schema,omitempty"` // Schema defining the type
}
Parameter represents a single parameter for an operation.
type PathFunc ¶ added in v0.12.0
PathFunc builds the path of a named route from arguments, as RoutePathArgs does. Router.RoutePathArgs method values are assignable to it, including those of the routers For and At return:
var paths router.PathFunc = news.At("/en/news").RoutePathArgs
paths("show", "slug", "hello") // "/en/news/hello"
Code that only builds links, such as a list rendered under different prefixes, can take a PathFunc instead of a *Router.
type PathItem ¶
type PathItem struct {
Get *Operation `json:"get,omitempty"` // GET operation
Head *Operation `json:"head,omitempty"` // HEAD operation
Post *Operation `json:"post,omitempty"` // POST operation
Put *Operation `json:"put,omitempty"` // PUT operation
Delete *Operation `json:"delete,omitempty"` // DELETE operation
Patch *Operation `json:"patch,omitempty"` // PATCH operation
Options *Operation `json:"options,omitempty"` // OPTIONS operation
}
PathItem describes the operations available on a single path.
type RequestBody ¶
type RequestBody struct {
Description string `json:"description,omitempty"` // Request body description
Content map[string]MediaType `json:"content"` // Media types supported by the request
Required bool `json:"required,omitempty"` // Is request body required?
}
RequestBody represents a request body for an operation.
type Response ¶
type Response struct {
Description string `json:"description" validate:"required"` // Response description
Content map[string]MediaType `json:"content,omitempty"` // Media types produced by the response
}
Response describes a single response from an API operation.
type RouteError ¶ added in v0.9.0
type RouteError struct {
Err any
}
func (RouteError) Error ¶ added in v0.9.0
func (e RouteError) Error() string
type RouteInfo ¶ added in v0.9.0
type RouteInfo struct {
Method string
// Path is the route's path for reverse routing: the registered
// pattern without {$}, so "/admin/{$}" and "/admin/" are "/admin/".
Path string
// Pattern is the registered ServeMux pattern, such as "/admin/{$}".
Pattern string
Host string
Name string
Handler http.Handler
Middlewares []Middleware
// Labels are the labels of the route and of the mounts it is below
// (RouteRegistration.Label).
Labels []string
// Mount reports that the registration is a mount (Mount, ServeAt)
// rather than a route. Match and MatchedRoute report the mount of a
// mounted router for the requests none of its routes matches.
Mount bool
// Redirect is set by Match and Owns for a path the
// router redirects before the route serves it: the path the
// redirects lead to, such as "/theme/" for "/theme" with a route
// "/theme/{file...}", or "/admin/users" for "/admin//users". It is
// "" for a path served as it is, and in Walk and MatchedRoute.
Redirect string
}
func MatchedRoute ¶ added in v0.12.0
MatchedRoute returns the route that served req, as the router the request entered has it: its public path and pattern, below the mount paths of the routers it is mounted on, its name and its labels. It is meant for UseAll middleware, after the request was served, such as an access log or metrics that label requests by route:
r.TrackRoutes()
r.UseAll(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
next.ServeHTTP(w, req)
route, ok := router.MatchedRoute(req)
class := "unmatched"
if ok {
class = route.Name
}
// ...
})
})
A request that entered a mounted router, also one served at a prefix (ServeAt), but none of its routes, such as a 404 or 405 answer of the mounted router or a redirect or answer of its UseAll middleware, reports the mount (RouteInfo.Mount), with its labels: requests below a mount are the mount's, also those the mounted router does not know. Other mounted handlers are routes of their own, with Mount set as well. It reports false for the requests the router answered without a route or mount: its own 404 and 405 answers and NotFound and MethodNotAllowed handlers, trailing slash redirects, and requests UseAll middleware answered itself.
The router records the route when it, or a router mounted on it, has TrackRoutes set, which costs two allocations per request; otherwise MatchedRoute reports false, except for requests of mounted routers. In route middleware and handlers req.Pattern gives the matched ServeMux pattern as well.
type RouteRegistration ¶ added in v0.9.0
type RouteRegistration struct {
// contains filtered or unexported fields
}
func (*RouteRegistration) As ¶ added in v0.9.0
func (rr *RouteRegistration) As(name string) *RouteRegistration
As names the route, for reverse routing (RoutePath, RoutePathArgs, the route template function and the like), and returns it, so calls chain: r.Get("/users/{id}", show).As("users.show").Use(auth). A name can only be given to one route; As panics on a name in use, and after the first request. TryAs returns an error instead.
func (*RouteRegistration) Label ¶ added in v0.12.0
func (rr *RouteRegistration) Label(labels ...string) *RouteRegistration
Label gives the route labels, such as "asset" or "admin", for whatever needs to tell routes apart by kind: metrics, access logs, checks of which paths are taken. They are in RouteInfo.Labels for Walk, Match and MatchedRoute:
r.ServeFiles("/assets/", assets).As("assets").Label("asset")
r.Mount("/admin", admin).Label("admin") // every route of admin
Labels of a mounted router (Mount) are given to all of its routes as this router sees them. Label panics after the first request.
func (*RouteRegistration) TryAs ¶ added in v0.9.0
func (rr *RouteRegistration) TryAs(name string) (err error)
TryAs is As returning an error instead of panicking, such as for a name another route has.
func (*RouteRegistration) TryLabel ¶ added in v0.12.0
func (rr *RouteRegistration) TryLabel(labels ...string) (err error)
TryLabel is Label returning an error instead of panicking.
func (*RouteRegistration) TryUse ¶ added in v0.12.0
func (rr *RouteRegistration) TryUse(middlewares ...Middleware) (err error)
TryUse is Use returning an error instead of panicking.
func (*RouteRegistration) Use ¶ added in v0.12.0
func (rr *RouteRegistration) Use(middlewares ...Middleware) *RouteRegistration
Use adds middleware to this route only. Route middleware runs inside the middleware of the router and its groups, in the order given, and after middleware of earlier Use calls on the route:
r.Use(a)
r.Group("/admin", func(admin *router.Router) {
admin.Use(b)
admin.Get("/users", users).Use(c, d).As("admin.users")
})
// a, b, c, d, users
It only runs for requests the route matched; on a Mount, that is every request of the mount, also those the mounted router answers without a route. NotFound and MethodNotAllowed handlers do not run inside route middleware, only inside that of the router or group they are set on. Use panics after the first request; TryUse returns an error instead.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
func NewSite ¶ added in v0.12.0
NewSite returns a router for websites: it has its own ServeMux and OpenAPI documentation is off, so there is no API title or version to give. UseOpenapiDocs can still turn documentation on.
func (*Router) AddServerEndpoint ¶
AddServerEndpoint adds a server, its URL and description, to the OpenAPI document of the router. A group, host or With router adds it to the document of the router it belongs to.
func (*Router) At ¶ added in v0.12.0
At returns r for reverse routing below prefix without a request: the paths For gives in the handlers of a request that r serves at prefix (ServeAt), for links built elsewhere, such as in a search index, a feed or a block on another page that lists a module's items:
news.At("/en/news").RoutePathArgs("show", "slug", "hello") // "/en/news/hello"
news.At("/en/news").RoutePath("index") // "/en/news"
RoutePath, RoutePathWithParams, RoutePathArgs, RouteURL, HasRoute, IsActiveRoute, FuncMap and their variants give public paths below prefix. As with ServeAt, prefix is the public path of r's root route, "/" or "/{$}", as given: At("/en/news") has it at /en/news, without a trailing slash, and At("/en/") at /en/; r's other routes are below prefix without its trailing slash. An empty prefix is "/", where r's paths are its own.
prefix is a path used as it is given, as ServeAt uses it: it is not escaped, while the parameters filled in below it are. Give it the way it goes into a link, and without { or }.
The router At returns is for reverse routing only. It resolves r's own route names, as For does, and is for a router that is not mounted with Mount, as ServeAt is.
func (*Router) Delete ¶
func (r *Router) Delete(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
func (*Router) For ¶ added in v0.12.0
For returns r for reverse routing in the handlers of a request that r serves at a prefix (ServeAt): RoutePath, RoutePathWithParams, RoutePathArgs, RouteURL, HasRoute, IsActiveRoute, FuncMap and their variants give the public paths of r's routes for req, below its prefix:
routes.Get("/{slug}", func(w http.ResponseWriter, req *http.Request) {
self, _ := routes.For(req).RoutePathArgs("show", "slug", req.PathValue("slug"))
// "/en/news/hello"
}).As("show")
The root route, "/" or "/{$}", is at the prefix exactly as ServeAt was given it: "/en/news" without a trailing slash, so a link or a form action to the page itself is not redirected to it, and "/en/" with one. At gives the same paths without a request.
For any other request it returns r itself. The router For returns is for reverse routing only.
func (*Router) FuncMap ¶ added in v0.9.0
FuncMap returns template functions for named routes:
- routePath name: the route's pattern, such as "/users/{id}"
- route name [key value]... [params map] [query url.Values]: the route's path with its parameters filled in, and a query string; an unknown route, a missing or an unknown parameter fails the template. See RoutePathArgs
- hasRoute name: whether the route exists (HasRoute), for links to routes that are optional
- routeOr name fallback [args]...: route, or fallback for an unknown route, without an error or a warning; parameter errors of a route that exists still fail the template
- routePathWithParams name params: RoutePathWithParams
- routeHost name: RouteHost
- routeURL name params scheme: RouteURL
- isActiveRoute current name [args]...: whether current is the route's path or below it (IsActiveRoute); isActiveRouteExact current name [args]...: whether it is the route's path (IsActiveRouteExact)
- isActiveRouteContains current substr: whether current's path contains substr
current is a *url.URL, a url.URL, an *http.Request or a path or URL string.
func (*Router) Get ¶
func (r *Router) Get(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
func (*Router) Handle ¶ added in v0.9.0
func (r *Router) Handle(pattern string, handler http.Handler) *RouteRegistration
Handle serves handler at pattern, a ServeMux pattern that may start with a method, such as "/feed.xml", "/theme/" or "GET /files/{path...}", and returns the route, so it can be named, labelled and get route middleware. The handler sees the full request URL, also in a mounted router; see Mount for a handler that wants the path below a prefix.
func (*Router) HandleFunc ¶ added in v0.9.0
func (r *Router) HandleFunc(pattern string, handler http.HandlerFunc) *RouteRegistration
HandleFunc is Handle for a handler function.
func (*Router) HandleStatus ¶ added in v0.2.0
func (r *Router) HandleStatus(httpStatus int, handler http.HandlerFunc)
HandleStatus registers a handler for responses with the given status, such as the 404 and 405 answers of the router and the 404s of handlers: the response is dropped and handler answers instead. A handler keeps its own response with NoIntercept. Status handlers run inside UseAll middleware, but not inside the middleware of Use (see Use for what that covers).
func (*Router) HasRoute ¶ added in v0.12.0
HasRoute reports whether a route has the given name, so a template or handler can leave out a link to a route that may not exist, such as a route of an optional module.
func (*Router) Head ¶
func (r *Router) Head(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
func (*Router) IsActiveRoute ¶ added in v0.12.0
IsActiveRoute reports whether current is the path of the named route or a path below it, for navigation: a route at /admin/news is active on /admin/news and /admin/news/7/edit, but not on /admin/newsletter. A route whose path ends in a slash, such as /admin/, is active below it.
current is a *url.URL, a url.URL, an *http.Request (its URL) or a string with a path or URL, such as the page URL an htmx request reports. A nil URL or request is not active.
The route's wildcards match any value, unless args gives theirs, as key value pairs or maps of parameters as for RoutePathArgs; url.Values in args are ignored:
r.IsActiveRoute(req, "users.show") // on /users/7 and /users/8/posts r.IsActiveRoute(req, "users.show", "id", 7) // on /users/7, not /users/8
An unknown route is not active and not an error, so navigation can name optional routes. It returns an error for invalid args, a parameter the route does not have and a current of another type.
func (*Router) IsActiveRouteExact ¶ added in v0.12.0
IsActiveRouteExact is IsActiveRoute without the paths below the route: whether current is the path of the named route.
func (*Router) Match ¶ added in v0.12.0
Match returns the route a request with the given method and path would be served by, on the router's default host, as Walk lists it: routes of mounted routers below their mount path. A query string in path is ignored. It reports false when no route matches, and for a router's own 404 and 405 answers.
A path the router redirects, the way the ServeMux redirects a path that is not clean ("/admin//users" to "/admin/users") or one without the trailing slash a route has ("/theme" for "/theme/{file...}"), and the way RedirectTrailingSlash removes one, is matched where the redirect leads, with RouteInfo.Redirect set to that path:
r.Get("/theme/{file...}", theme).Label("asset")
r.Match(http.MethodGet, "/theme") // GET /theme/{file...}, Redirect "/theme/"
A mounted router is not a route of its own, its routes are; for a path below its mount path that none of them matches for the method, Match returns the mount, as Walk lists it, with RouteInfo.Mount set and the mount's labels:
r.Mount("/admin", admin).Label("admin")
r.Match(http.MethodGet, "/admin/users/7") // admin.users.show, /admin/users/{id}
r.Match(http.MethodGet, "/admin/nothing") // the mount, /admin/, labelled admin
Use Owns for a path with any method, and MatchLabel when only the route's labels matter.
func (*Router) MatchLabel ¶ added in v0.12.0
MatchLabel returns a label of the route Match reports, without copying the route: the first of the route's labels that is one of labels, or its first label when no labels are given, and "" when it has none of them. ok is what Match reports. It is the cheap way to tell which part of an application a path belongs to:
class, ok := r.MatchLabel(http.MethodGet, path, "admin", "asset", "media")
func (*Router) MethodNotAllowed ¶
MethodNotAllowed sets the handler for requests whose path has routes, but not for the request's method. It is set and applies like NotFound.
The router sets the Allow header with those methods before the handler runs, so the handler can read them, and keeps it when the handler answers 405 Method Not Allowed. It removes the header when the handler answers with another status, such as a not found page for every unmatched request, unless the handler changed it:
r.MethodNotAllowed(notFoundPage) // a 404, without Allow
func (*Router) Mount ¶ added in v0.9.0
func (r *Router) Mount(pattern string, handler http.Handler, options ...MountOption) *RouteRegistration
Mount serves handler at pattern and below it, and returns the mount as a route, so it can be named, labelled and get route middleware that runs for every request of the mount.
A handler that is not a *Router sees the path without the mount path, as with http.StripPrefix (see AbsolutePaths).
A *Router becomes part of this router: its routes, route names, hosts and OpenAPI paths, registered before or after Mount, show up here below the mount path, and it is frozen with this router on the first request. Its handlers and middleware see the full request URL, as this router received it, and its reverse routing (RoutePath, RoutePathWithParams, RoutePathArgs, FuncMap and the like) resolves through the outermost router it is mounted on, so it gives the paths the routes are served at, and can reach the names of the routers it is mounted on. The mount path itself and the mount path with a trailing slash both reach the mounted router's "/" or "/{$}".
A handler with a Router() *Router method, such as a type that wraps its router in middleware of its own, is mounted as that router, and requests are served through the handler: the handler sees the full request URL, and the router matches below the mount path when the handler passes the request on to it.
Labels given to the mount (RouteRegistration.Label) are given to every route of a mounted router as well. See NamePrefix and AbsolutePaths for the options.
func (*Router) NotFound ¶
NotFound sets the handler for requests that no route matches: neither the path nor, for a 404, the path with another method. It answers only those, not routes that answer 404 themselves, and is not a route: it is not in Walk, it does not keep Use from being called, and a route of the router takes precedence over it. It runs inside the router's UseAll middleware and inside the Use middleware of the router or group it is set on, also middleware added after NotFound.
Set on a group or host router, it answers the unmatched requests below the group's path or on its host; the most specific one answers:
r.NotFound(siteNotFound)
r.Group("/api", func(api *router.Router) {
api.NotFound(jsonNotFound) // /api/...
})
A router mounted on another (Mount) answers its unmatched requests with its own NotFound handlers, or else with those of the routers it is mounted on, which see the request URL as the outer router received it. Those run without the Use middleware of their router again: the request passed it through the mount. The response is not replaced by HandleStatus handlers. NotFound panics after the first request. See MethodNotAllowed for 405 answers.
A router that serves "/" itself, such as with r.Handle("/", site) or a router mounted at "/", leaves its unmatched requests to that handler.
func (*Router) OperationID ¶
func (*Router) Options ¶ added in v0.9.0
func (r *Router) Options(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
func (*Router) Owns ¶ added in v0.12.0
Owns returns the registration that receives requests for path on the router's default host, with any method: the most specific route that path has, or, as Match reports it, the mount of a mounted router that has no route for path. It reports false when nothing would receive path. A query string in path is ignored. A path the router redirects is received by what the redirect leads to, with RouteInfo.Redirect set, as Match reports it.
It answers which part of an application a path belongs to, such as a path below a mount, or a path a site must not give a page of its own:
r.Mount("/admin", admin).Label("admin")
r.Post("/login", login).Label("auth")
r.Handle("/", site)
r.Owns("/admin/anything") // the mount, labelled admin
r.Owns("/login") // POST /login, not the site that GET reaches
r.Owns("/about") // the site, "/"
Of two routes, the more specific one is the one with a literal segment where the other has a wildcard, then the one with more segments, then the one that does not match the paths below it; of equally specific routes, the first of GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, CONNECT, TRACE and other methods. Owns tries the methods the routes have one by one, so it costs about as much as a Match per method; Match is cheaper when the method is known. OwnsLabel gives the labels only.
func (*Router) OwnsLabel ¶ added in v0.12.0
OwnsLabel returns a label of the registration Owns reports, without copying it: the first of its labels that is one of labels, or its first label when no labels are given, and "" when it has none of them. ok is what Owns reports.
func (*Router) Patch ¶
func (r *Router) Patch(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
func (*Router) Post ¶
func (r *Router) Post(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
func (*Router) Put ¶
func (r *Router) Put(pattern string, handler http.HandlerFunc, doc ...Docs) *RouteRegistration
func (*Router) RedirectTrailingSlash ¶
func (*Router) RouteHost ¶ added in v0.9.0
RouteHost returns the host pattern of the named route, or "".
func (*Router) RoutePath ¶ added in v0.9.0
RoutePath returns the path pattern of the named route, such as "/users/{id}", or "" for an unknown route. A router mounted on another returns the path the route is served at, below the mount path.
func (*Router) RoutePathArgs ¶ added in v0.12.0
RoutePathArgs is the route template function of FuncMap as a Go function: the path of the named route with its parameters filled in, from key value pairs, maps of parameters (map[string]any or map[string]string) and url.Values for the query string, in any order and combination:
r.RoutePathArgs("users.show", "id", 42)
r.RoutePathArgs("users.posts.show", map[string]any{"id": 1, "post": 2})
r.RoutePathArgs("search", url.Values{"q": {"go"}})
Later values replace earlier ones for the same parameter; query values are combined. It returns an error wrapping ErrUnknownRoute, ErrMissingParam or ErrUnknownParam for an unknown route, a parameter without a (non-empty) value, or a parameter the route does not have, and an error for a key without a value or an argument of another type. The subdomain and tenant parameters of a wildcard subdomain route are accepted and ignored.
func (*Router) RoutePathWithParams ¶ added in v0.9.0
RoutePathWithParams returns the path of the named route with its parameters filled in: {name} with the URL-escaped value and {name...} with the value's segments, each URL-escaped, so slashes are kept. A {name...} value is a string, split on "/", or a []string of segments.
It returns "" for an unknown route. A parameter without a value is left as its placeholder. Both are reported to slog.Default(). Use RoutePathArgs, which takes the same map, to get errors instead, and to add a query string.
func (*Router) RouteTable ¶ added in v0.9.0
func (*Router) RouteURL ¶ added in v0.9.0
RouteURL returns the URL of the named route: scheme://host/path for a host route, //host/path without a scheme, and just the path for a route without a host. A wildcard subdomain is filled from the subdomain or tenant parameter. Parameters are handled as in RoutePathWithParams.
func (*Router) ServeAt ¶ added in v0.12.0
func (r *Router) ServeAt(w http.ResponseWriter, req *http.Request, prefix string, options ...MountOption)
ServeAt serves req with r as if r were mounted at prefix, for this request only: for a router whose place is not known when routes are registered, such as the router of a module on a page of a CMS, whose address editors can change. The handler that calls ServeAt decides where the router is:
site.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
page := pages.Resolve(req.URL.Path) // such as "/en/news"
page.Module.Routes.ServeAt(w, req, page.Path)
}))
Requests at prefix and below it are served as by Mount: r matches with the path below prefix, its handlers and middleware see the request URL as the handler that calls ServeAt received it, the public URL, and MatchedRoute gives r's routes below prefix, as Mount would ("/{slug}" as "/en/news/{slug}", "/{$}" as "/en/news/{$}"), with the labels of the route that called ServeAt. Other requests get a 404. Use For in r's handlers for reverse routing with public paths.
prefix is the public path of r's root route, "/" or "/{$}", as given: "/en/news" has it at /en/news, "/en/" at /en/. Its other routes are below prefix without its trailing slash, such as /en/news/{slug}.
NamePrefix puts a prefix before r's route names as MatchedRoute reports them to the routers the request came through; AbsolutePaths does not apply. r should not be mounted with Mount as well.
func (*Router) ServeFile ¶
func (r *Router) ServeFile(pattern string, filepath string) *RouteRegistration
ServeFile serves the file at filepath with GET at pattern, and returns the route, so it can be named and get route middleware.
func (*Router) ServeFiles ¶
func (r *Router) ServeFiles(pattern string, fs http.FileSystem) *RouteRegistration
ServeFiles serves the files of fs with GET below pattern, and returns the route, so it can be named and get route middleware. The route's pattern ends in a rest wildcard, {file...} unless pattern ends in one of its own, which gives the file's path when the route is reversed:
r.ServeFiles("/assets/", http.FS(assets)).As("assets")
r.RoutePathArgs("assets", "file", "css/site.css") // "/assets/css/site.css"
r.ServeFiles("/static/{path...}", http.Dir("static")).As("static")
r.RoutePathArgs("static", "path", "logo.svg") // "/static/logo.svg"
"/assets", "/assets/" and "/assets/{file...}" are the same route. The file server gets the wildcard's value as its path, so ServeFiles works the same in groups, hosts and mounted routers.
func (*Router) TrackRoutes ¶ added in v0.12.0
func (r *Router) TrackRoutes()
TrackRoutes has the router record which route serves each request, for MatchedRoute and MatchedLabel, in UseAll middleware and in the routes' own middleware and handlers. It costs two allocations per request, the request with its state in the context, so it is off by default. A router mounted on another with TrackRoutes has the router it is mounted on record its requests too. TrackRoutes panics after the first request.
func (*Router) TryDelete ¶ added in v0.9.0
func (r *Router) TryDelete(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
func (*Router) TryGet ¶ added in v0.9.0
func (r *Router) TryGet(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
func (*Router) TryHandle ¶ added in v0.9.0
func (r *Router) TryHandle(pattern string, handler http.Handler) (routeRegistration *RouteRegistration, err error)
TryHandle is Handle returning an error instead of panicking, such as for a pattern registered twice. The route is nil when err is set.
func (*Router) TryHandleFunc ¶ added in v0.9.0
func (r *Router) TryHandleFunc(pattern string, handler http.HandlerFunc) (*RouteRegistration, error)
TryHandleFunc is HandleFunc returning an error instead of panicking.
func (*Router) TryHead ¶ added in v0.9.0
func (r *Router) TryHead(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
func (*Router) TryMount ¶ added in v0.9.0
func (r *Router) TryMount( pattern string, handler http.Handler, options ...MountOption, ) (routeRegistration *RouteRegistration, err error)
TryMount is Mount returning an error instead of panicking, such as for a mount path taken by another mount or route of the same pattern, a router mounted on itself, or route names of the mounted router that this router has already. The mount is nil when err is set; otherwise it can be labelled and get middleware as Mount's:
mount, err := r.TryMount("/admin", admin, router.AbsolutePaths())
if err != nil {
return err
}
if err := mount.TryLabel("admin"); err != nil {
return err
}
func (*Router) TryOptions ¶ added in v0.9.0
func (r *Router) TryOptions(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
func (*Router) TryPatch ¶ added in v0.9.0
func (r *Router) TryPatch(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
func (*Router) TryPost ¶ added in v0.9.0
func (r *Router) TryPost(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
func (*Router) TryPut ¶ added in v0.9.0
func (r *Router) TryPut(pattern string, handler http.HandlerFunc, doc ...Docs) (*RouteRegistration, error)
func (*Router) Use ¶
func (r *Router) Use(middleware Middleware)
Use adds middleware to the routes registered on this router (and its groups) after the call. Middleware is applied when a route is registered, so Use must come before the routes: it panics when routes were already registered on this router or on one of its groups, since those would silently miss the middleware. Use Group or With for routes that need different middleware, or Use on a single route (RouteRegistration.Use).
Use middleware runs around the handlers registered after it on this router and its groups:
- its routes, and every request of a Mount, which is a route as well, so also the requests a mounted router answers without a route of its own, such as its 404 answers;
- the NotFound and MethodNotAllowed handlers set on this router or one of its groups, also when they were set before Use (the router builds their chain when it freezes).
It does not run for what the router answers without a handler: its plain 404 and 405 answers when no NotFound or MethodNotAllowed handler applies, trailing slash redirects and the redirects of the ServeMux (such as unclean paths), nor for HandleStatus handlers and requests that UseAll middleware answers itself. UseAll, or wrapping the router itself, as in http.ListenAndServe(addr, middleware.RequestID(r)), covers every request.
func (*Router) UseAll ¶ added in v0.12.0
func (r *Router) UseAll(middlewares ...Middleware)
UseAll adds middleware around the whole router: unlike Use, it runs for every request the router serves, before a route is matched, so also for trailing slash redirects and other redirects, the router's plain 404 and 405 answers and HandleStatus handlers, next to routes and NotFound and MethodNotAllowed handlers. It is the same as wrapping the router, r.UseAll(a, b) serves as a(b(r)), and suits request IDs, logging, recovery and real IP middleware:
r.UseAll(middleware.RequestID, middleware.Logger(), middleware.Recover)
UseAll middleware runs before the route is matched: req.PathValue is empty and Use middleware has not run yet. A router mounted on another runs its UseAll middleware for the requests that reach it, with the request URL as the outer router received it, like its routes.
UseAll can be called after routes were registered, but only on the router itself, not on a group, With or host router, since it applies to all of the router's requests. It panics on those and after the first request.
func (*Router) UseOpenapiDocs ¶
func (*Router) WildcardSubdomain ¶ added in v0.9.0
type Schema ¶
type Schema struct {
Ref string `json:"$ref,omitempty"` // Reference to a schema
Type string `json:"type,omitempty"` // Data type (e.g., "string", "object")
Format string `json:"format,omitempty"` // Data format (e.g., "uuid", "email")
Properties map[string]Schema `json:"properties,omitempty"` // Properties of the object
Items *Schema `json:"items,omitempty"` // Schema for array items
AdditionalProperties *Schema `json:"additionalProperties,omitempty"` // Schema for map values
Required []string `json:"required,omitempty"` // Required properties
Enum []any `json:"enum,omitempty"` // Allowed values
Nullable bool `json:"nullable,omitempty"` // Whether the value can be null
}
Schema represents the structure of a request or response body.
type SecurityScheme ¶
type SecurityScheme struct {
Type string `json:"type" validate:"required"` // Security scheme type (e.g., "http", "apiKey")
Scheme string `json:"scheme,omitempty"` // HTTP Authorization scheme (e.g., "bearer")
BearerFormat string `json:"bearerFormat,omitempty"` // Bearer token format
}
SecurityScheme defines a security scheme for the API.
type Server ¶
type Server struct {
URL string `json:"url" validate:"required"` // Server URL
Description string `json:"description,omitempty"` // Server description
Variables map[string]string `json:"variables,omitempty"` // Variables for URL template
}
Server represents an API server.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
example
|
|
|
openapi
command
|
|
|
production
command
|
|
|
simple
command
|
|
|
Package middleware holds net/http middleware for go-router and any other http.Handler: request IDs, logging through log/slog, recovery, the client IP behind trusted proxies, security headers and Content-Security-Policy, CORS, compression, ETags and Last-Modified checks, an output cache, and rate and body limits.
|
Package middleware holds net/http middleware for go-router and any other http.Handler: request IDs, logging through log/slog, recovery, the client IP behind trusted proxies, security headers and Content-Security-Policy, CORS, compression, ETags and Last-Modified checks, an output cache, and rate and body limits. |