A drop-in replacement for Go's http.ServeMux
with all the missing features
PowerMux stores routes in radix trees for fast route matching and lookup on large numbers of routes.
PowerMux requires at least Go version 1.8.
In all cases, PowerMux does not support routes with a trailing slash /
other than the root node.
Requests to paths that end in a slash are automatically redirected using a permanent redirection.
You can use PowerMux exactly as you would use Go's server mux.
// Golang default
mux := http.NewServeMux()
mux.Handle("/", myHandler)
// PowerMux
mux := powermux.NewServeMux()
mux.Handle("/", myHandler)
PowerMux also has a cleaner way to declare routes, using the Route
function.
Each call to Route()
returns a pointer to that particular path on the radix tree, creating it if necessary.
At each route, you can add middleware, set handlers, or descend further into the route:
mux := powermux.NewServeMux()
// Set a GET handler for "/"
mux.Route("/").Get(myHandler)
// Set POST/DELETE handlers for "/"
mux.Route("/").
Post(myPostHandler).
Delete(myDeleteHandler)
Sequential calls to route have the same effect as a single call with a longer path:
mux.Route("/a").Route("/b").Route("/c") == mux.Route("/a/b/c")
Since Handler methods also return the route, the syntax can also be chained like so:
mux.Route("/").
Get(rootHandler).
Route("/a").
Get(aGetHandler).
Post(aPostHandler).
Route("/b").
Get(abGetHandler)
PowerMux has support for any kind of middleware that uses the common func(res, req, next)
syntax.
Middleware handler objects must implement the ServeHTTPMiddleware
interface.
Middleware will always be executed before any handlers, including default or generated not found handlers.
Middleware can be added to any route:
mux.Route("/users").
Middleware(authMiddleware).
Get(sensitiveInfoHandler)
// or
mux.Route("/books").MiddleWare(loggingMiddleware)
mux.Route("/books").Get(booksHandler)
Middleware will be run if it's attached to any part of the route above and including the final path:
mux.Route("/").Middleware(midRoot)
mux.Route("/a").Middleware(midA)
mux.Route("/a/b").Middleware(midB)
mux.Route("/c").Middleware(midC)
// requests to /a/b will run midRoot, midA, midB,
// then any handlers on Route("/a/b")
Middleware can also be set up to selectively execute based on the HTTP method of the request.
The middleware function variants MiddlewareFor
and MiddlewareExceptFor
either set middleware to execute on only
specified methods, on all methods except the specified ones respectively.
// don't run this middleware on OPTIONS requests
mux.Route("/a").MiddlewareExceptFor(ignoreCorsMid, http.MethodOptions)
Unlike the Go default multiplexer, host specific routes need to be handled separately. Use the *Host
variants of
common functions to achieve this.
mux.Route("/test")
mux.RouteHost("example.com", "/text")
// request to any host other than example.com will go to the first handler
Options
and NotFound
handlers are treated specially. If one is not found on the Route node requested,
the latest one above that node will be used. This allows whole sections of routes to be covered under custom CORS
responses or Not Found handlers
Routes may include path parameters, specified with /:name
:
mux.Route("/users/:id/info").
Get(userInfoHander)
This will make the variable id
available to the get handler and any middleware.
To retrieve path parameters, use PathParam()
:
// called with /users/andrew/info
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
id := powermux.PathParam(r, "id")
// id == "andrew"
}
Path parameters that aren't found return an empty string.
Path parameters are unescaped with url.PathUnescape
.
Routes may be declared with a wildcard indicator *
at the end.
This will match any path that does not have a more specific handler registered.
mux.Route("/static/*").Get(staticContentHandler)
mux.Route("/static/favicon").Get(faviconGenerator)
// requests to /static will all be mapped to static content handler
// EXCEPT for requests to /static/favicon
Declaring a wildcard route at the same level as a path parameter route will never be executed as the path parameter takes greater precedence.
mux.Route("/users/:id") // valid
mux.Route("/users/*") // never matched
More routes may be specified after a wildcard, but they will never be executed:
r1 := mux.Route("/users/*") // valid
r1.Route("/further/paths") // never matched
If multiple routes are declared that could match a given path, they are selected in this order:
- A literal path
/users/andrew/info
- A path with parameters
/users/:id/info
- A wildcard path
/users/*
Handlers and Middleware may access the route pattern that was used by powermux to route any particular
request with the RequestPath
function.
servemux.Route("/users/:id/info").Get(userHandler)
...
// envoked with /users/andrew/info
func ServeHTTP(rw http.ResponseWriter, req *http.Request) {
originalPath := powermux.RequestPath(req)
originalPath == "/users/:id/info"
req.URL.Path == "/users/andrew/info"
}
When multiple handlers are declared on a single route for different methods, they are selected in this order:
- An exact method match
- HEAD requests can use GET handlers
- The ANY handler
- A generated Method Not Allowed handler