Documentation
¶
Overview ¶
Package router is a thin layer over net/http.ServeMux (Go 1.22+ patterns) adding route groups, named routes with URL generation, resource controllers and three middleware stacks:
- server middleware runs on every request, even when no route matches;
- router middleware runs only when a route matches;
- route/group middleware runs for the routes it is attached to.
Middleware has the standard signature func(http.Handler) http.Handler, so any net/http middleware works.
New returns a Router; Get, Post, Group and Resource register Route values whose handlers are web.HandlerFunc, and Router.Handler compiles them into an http.Handler. Apps receive the router in vukem.WithRoutes and reach named routes through Router.URL or the "route" template function.
See https://github.com/AlexGalhardo/vukem/blob/main/docs/http.md.
Example ¶
package main
import (
"fmt"
"log/slog"
"net/http"
"net/http/httptest"
"github.com/AlexGalhardo/vukem/router"
"github.com/AlexGalhardo/vukem/web"
)
func main() {
r := router.New(&web.Services{Log: slog.New(slog.DiscardHandler)})
r.Get("/posts/{id}", func(c *web.Ctx) error {
return c.String(http.StatusOK, "post "+c.Param("id"))
}).Name("posts.show")
h, err := r.Handler()
if err != nil {
fmt.Println(err)
return
}
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/posts/42", http.NoBody))
fmt.Println(rec.Code, rec.Body.String())
link, err := r.URL("posts.show", "id", 7)
fmt.Println(link, err)
}
Output: 200 post 42 /posts/7 <nil>
Index ¶
- func Adapt(h web.HandlerFunc, services *web.Services) http.Handler
- func Wrap(h http.Handler) web.HandlerFunc
- type Creator
- type Destroyer
- type Editor
- type Group
- func (g *Group) APIResource(name string, ctrl any) *Resource
- func (g *Group) Any(path string, h web.HandlerFunc) *Route
- func (g *Group) Delete(path string, h web.HandlerFunc) *Route
- func (g *Group) Get(path string, h web.HandlerFunc) *Route
- func (g *Group) Group(prefix string, fn func(g *Group)) *Group
- func (g *Group) Handle(pattern string, h http.Handler) *Route
- func (g *Group) Match(methods []string, path string, h web.HandlerFunc) []*Route
- func (g *Group) Name(prefix string) *Group
- func (g *Group) Options(path string, h web.HandlerFunc) *Route
- func (g *Group) Patch(path string, h web.HandlerFunc) *Route
- func (g *Group) Post(path string, h web.HandlerFunc) *Route
- func (g *Group) Put(path string, h web.HandlerFunc) *Route
- func (g *Group) Resource(name string, ctrl any) *Resource
- func (g *Group) Use(mw ...Middleware) *Group
- type Indexer
- type Middleware
- type Resource
- type Route
- type RouteInfo
- type Router
- func (r *Router) APIResource(name string, ctrl any) *Resource
- func (r *Router) Any(path string, h web.HandlerFunc) *Route
- func (r *Router) Compiled() bool
- func (r *Router) Delete(path string, h web.HandlerFunc) *Route
- func (r *Router) Get(path string, h web.HandlerFunc) *Route
- func (r *Router) Group(prefix string, fn func(g *Group)) *Group
- func (r *Router) Handle(pattern string, h http.Handler) *Route
- func (r *Router) Handler() (http.Handler, error)
- func (r *Router) Match(methods []string, path string, h web.HandlerFunc) []*Route
- func (r *Router) Options(path string, h web.HandlerFunc) *Route
- func (r *Router) Patch(path string, h web.HandlerFunc) *Route
- func (r *Router) Post(path string, h web.HandlerFunc) *Route
- func (r *Router) Put(path string, h web.HandlerFunc) *Route
- func (r *Router) Resource(name string, ctrl any) *Resource
- func (r *Router) Routes() []RouteInfo
- func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
- func (r *Router) Services() *web.Services
- func (r *Router) URL(name string, params ...any) (string, error)
- func (r *Router) Use(mw ...Middleware)
- func (r *Router) UseServer(mw ...Middleware)
- type Shower
- type Storer
- type Updater
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Group ¶
type Group struct {
// contains filtered or unexported fields
}
Group is a set of routes sharing a path prefix, a name prefix and middleware. Groups nest.
func (*Group) APIResource ¶
APIResource is Resource without the create and edit form routes.
func (*Group) Any ¶
func (g *Group) Any(path string, h web.HandlerFunc) *Route
Any registers path for every method.
func (*Group) Delete ¶
func (g *Group) Delete(path string, h web.HandlerFunc) *Route
Delete registers a DELETE route.
func (*Group) Get ¶
func (g *Group) Get(path string, h web.HandlerFunc) *Route
Get registers a GET route (it also answers HEAD).
func (*Group) Options ¶
func (g *Group) Options(path string, h web.HandlerFunc) *Route
Options registers an OPTIONS route.
func (*Group) Patch ¶
func (g *Group) Patch(path string, h web.HandlerFunc) *Route
Patch registers a PATCH route.
func (*Group) Post ¶
func (g *Group) Post(path string, h web.HandlerFunc) *Route
Post registers a POST route.
func (*Group) Put ¶
func (g *Group) Put(path string, h web.HandlerFunc) *Route
Put registers a PUT route.
func (*Group) Resource ¶
Resource registers RESTful routes for ctrl under /name. Nested resources use dots: "posts.comments" → /posts/{post}/comments/{comment}. Route names are "<name>.<action>".
func (*Group) Use ¶
func (g *Group) Use(mw ...Middleware) *Group
Use appends middleware applied to every route of the group (including routes registered before the call and in nested groups).
type Middleware ¶
Middleware wraps an http.Handler.
type Resource ¶
type Resource struct {
// contains filtered or unexported fields
}
Resource is a set of routes generated from a controller.
func (*Resource) Shallow ¶
Shallow makes the member routes of a nested resource top-level, as their IDs are unique on their own: /posts/{post}/comments stays for index/create/store, while show/edit/update/destroy become /comments/{comment}. Route names do not change.
func (*Resource) Use ¶
func (rs *Resource) Use(mw ...Middleware) *Resource
Use applies middleware to the resource routes (all actions when none are given by Only/Except before).
type Route ¶
type Route struct {
// contains filtered or unexported fields
}
Route is a registered route.
func (*Route) Doc ¶ added in v0.15.0
Doc attaches documentation (e.g. an api.Operation) that generators such as the OpenAPI exporter read back through RouteInfo.Doc.
func (*Route) Name ¶
Name sets the route name used by URL generation. The names of enclosing groups are prefixed when the router is compiled.
type RouteInfo ¶
type RouteInfo struct {
Method string `json:"method"`
Path string `json:"path"`
Name string `json:"name,omitempty"`
// LocalName is the name given to the route itself, without the group
// name prefixes (Name is the full name).
LocalName string `json:"-"`
Middleware []string `json:"middleware,omitempty"`
Doc any `json:"-"`
}
RouteInfo describes a compiled route.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router collects routes and compiles them into an http.Handler.
func (*Router) APIResource ¶
APIResource is Resource without the create and edit form routes.
func (*Router) Any ¶
func (r *Router) Any(path string, h web.HandlerFunc) *Route
Any registers a route for every method.
func (*Router) Compiled ¶ added in v0.25.0
Compiled reports whether the routes were compiled (by Handler, URL or a first request). Routes added after that are not served.
func (*Router) Delete ¶
func (r *Router) Delete(path string, h web.HandlerFunc) *Route
Delete registers a DELETE route.
func (*Router) Get ¶
func (r *Router) Get(path string, h web.HandlerFunc) *Route
Get registers a GET route (it also answers HEAD).
func (*Router) Group ¶
Group creates a route group under prefix. Inside it, g.Get("/", h) serves prefix+"/" exactly (ServeMux redirects the bare prefix there) and g.Get("", h) serves the bare prefix; neither is a catch-all.
Example ¶
package main
import (
"fmt"
"log/slog"
"net/http"
"github.com/AlexGalhardo/vukem/router"
"github.com/AlexGalhardo/vukem/web"
)
func main() {
r := router.New(&web.Services{Log: slog.New(slog.DiscardHandler)})
r.Group("/admin", func(g *router.Group) {
g.Get("/dashboard", func(c *web.Ctx) error {
return c.String(http.StatusOK, "dashboard")
}).Name("dashboard")
}).Name("admin.")
for _, route := range r.Routes() {
fmt.Println(route.Method, route.Path, route.Name)
}
}
Output: GET /admin/dashboard admin.dashboard
func (*Router) Handle ¶
Handle mounts a plain http.Handler. pattern uses ServeMux syntax and may start with a method ("GET /metrics").
func (*Router) Handler ¶
Handler compiles the routes. It reports pattern conflicts, invalid patterns and duplicate names. Routes added afterwards are ignored.
func (*Router) Options ¶
func (r *Router) Options(path string, h web.HandlerFunc) *Route
Options registers an OPTIONS route.
func (*Router) Patch ¶
func (r *Router) Patch(path string, h web.HandlerFunc) *Route
Patch registers a PATCH route.
func (*Router) Post ¶
func (r *Router) Post(path string, h web.HandlerFunc) *Route
Post registers a POST route.
func (*Router) Put ¶
func (r *Router) Put(path string, h web.HandlerFunc) *Route
Put registers a PUT route.
func (*Router) Resource ¶
Resource registers the actions ctrl implements (see Indexer, Storer, ...).
func (*Router) ServeHTTP ¶
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
ServeHTTP compiles on first use and serves; it panics on a build error, so call Handler at boot to surface errors early.
func (*Router) URL ¶
URL implements web.URLGenerator: params are name/value pairs filling the route's {wildcards}. Missing or unknown params are errors.
func (*Router) Use ¶
func (r *Router) Use(mw ...Middleware)
Use appends middleware that runs for every matched route.
func (*Router) UseServer ¶
func (r *Router) UseServer(mw ...Middleware)
UseServer appends middleware that runs for every request.