powermux

package module
v1.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 23, 2021 License: MIT Imports: 8 Imported by: 4

README

PowerMux

Build Status codecov Release

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.

Dependencies

PowerMux requires at least Go version 1.8.

Setting up PowerMux

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.

Using http.ServeMux syntax

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)
Using the Route syntax

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)

Middleware

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)

Host specific routes

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

Not Found and OPTIONS handlers

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

Path Parameters

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.

Wildcard patterns

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

Route precedence

If multiple routes are declared that could match a given path, they are selected in this order:

  1. A literal path /users/andrew/info
  2. A path with parameters /users/:id/info
  3. A wildcard path /users/*

Retrieving the original route path

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"
}

Handler precedence

When multiple handlers are declared on a single route for different methods, they are selected in this order:

  1. An exact method match
  2. HEAD requests can use GET handlers
  3. The ANY handler
  4. A generated Method Not Allowed handler

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func PathParam

func PathParam(req *http.Request, name string) (value string)

PathParam gets named path parameters and their values from the request

the path '/users/:name' given '/users/andrew' will have `PathParam(r, "name")` => `"andrew"` unset values return an empty stringRoutes

func PathParams

func PathParams(req *http.Request) (params map[string]string)

PathParams returns the map of all path parameters and their values from the request.

Altering the values of this map will not affect future calls to PathParam and PathParams.

func RequestPath

func RequestPath(req *http.Request) (value string)

RequestPath returns the path definition that the router used to serve this request, without any parameter substitution.

Types

type Middleware

type Middleware interface {
	ServeHTTPMiddleware(http.ResponseWriter, *http.Request, func(http.ResponseWriter, *http.Request))
}

Middleware handles HTTP requests and optionally passes them along to the next handler in the chain.

type MiddlewareFunc

type MiddlewareFunc func(http.ResponseWriter, *http.Request, func(http.ResponseWriter, *http.Request))

The MiddlewareFunc type is an adapter to allow the use of ordinary functions as HTTP middlewares.

If f is a function with the appropriate signature, HandlerFunc(f) is a Handler that calls f.

func (MiddlewareFunc) ServeHTTPMiddleware

func (m MiddlewareFunc) ServeHTTPMiddleware(rw http.ResponseWriter, req *http.Request, n func(http.ResponseWriter, *http.Request))

ServeHTTPMiddleware calls f(w, r, n).

type Route

type Route struct {
	// contains filtered or unexported fields
}

A Route represents a specific path for a request. Routes can be absolute paths, rooted subtrees, or path parameters that accept any stringRoutes.

func (*Route) Any

func (r *Route) Any(handler http.Handler) *Route

Any registers a catch-all handler for any method sent to this route. This takes lower precedence than a specific method match.

func (*Route) AnyFunc

func (r *Route) AnyFunc(f http.HandlerFunc) *Route

AnyFunc registers a plain function as a catch-all handler for any method sent to this route. This takes lower precedence than a specific method match.

func (*Route) Connect

func (r *Route) Connect(handler http.Handler) *Route

Connect adds a handler for CONNECT methods to this route.

func (*Route) ConnectFunc

func (r *Route) ConnectFunc(f http.HandlerFunc) *Route

ConnectFunc adds a plain function as a handler for CONNECT methods to this route.

func (*Route) Delete

func (r *Route) Delete(handler http.Handler) *Route

Delete adds a handler for DELETE methods to this route.

func (*Route) DeleteFunc

func (r *Route) DeleteFunc(f http.HandlerFunc) *Route

DeleteFunc adds a plain function as a handler for DELETE methods to this route.

func (*Route) Get

func (r *Route) Get(handler http.Handler) *Route

Get adds a handler for GET methods to this route. GET handlers will also be called for HEAD requests if no specific HEAD handler is registered.

func (*Route) GetFunc

func (r *Route) GetFunc(f http.HandlerFunc) *Route

GetFunc adds a plain function as a handler for GET methods to this route. GET handlers will also be called for HEAD requests if no specific HEAD handler is registered.

func (*Route) Head

func (r *Route) Head(handler http.Handler) *Route

Head adds a handler for HEAD methods to this route.

func (*Route) HeadFunc

func (r *Route) HeadFunc(f http.HandlerFunc) *Route

HeadFunc adds a plain function as a handler for HEAD methods to this route.

func (*Route) Middleware

func (r *Route) Middleware(m Middleware) *Route

Middleware adds a middleware to this Route.

Middlewares are executed if the path to the target route crosses this route.

func (*Route) MiddlewareExceptFor added in v1.1.0

func (r *Route) MiddlewareExceptFor(m Middleware, verbs ...string) *Route

MiddlewareExceptFor adds a middleware to this node, but will only be executed for requests that are not in the list of verbs. Verbs are case sensitive, and should use the `http.Method*` constants. Panics if any of the verbs provided are unknown.

func (*Route) MiddlewareExceptForOptions added in v1.1.0

func (r *Route) MiddlewareExceptForOptions(m Middleware) *Route

MiddlewareExceptForOptions is shorthand for MiddlewareExceptFor with http.MethodOptions as the only excepted method

func (*Route) MiddlewareFor added in v1.1.0

func (r *Route) MiddlewareFor(m Middleware, verbs ...string) *Route

MiddlewareFor adds a middleware to this node, but will only be executed for requests with the verb specified. Verbs are case sensitive, and should use the `http.Method*` constants. Panics if any of the verbs provided are unknown.

func (*Route) MiddlewareFunc

func (r *Route) MiddlewareFunc(m MiddlewareFunc) *Route

MiddlewareFunc registers a plain function as a middleware.

func (*Route) NotFound

func (r *Route) NotFound(handler http.Handler) *Route

NotFound adds a handler for requests that do not correspond to a route. This handler will also be called for any routes further down the path from this point if no other not found handlers are registered below.

func (*Route) NotFoundFunc

func (r *Route) NotFoundFunc(f http.HandlerFunc) *Route

NotFoundFunc adds a plain function as a handler for requests that do not correspond to a route. This handler will also be called for any routes further down the path from this point if no other not found handlers are registered below.

func (*Route) Options

func (r *Route) Options(handler http.Handler) *Route

Options adds a handler for OPTIONS methods to this route. This handler will also be called for any routes further down the path from this point if no other OPTIONS handlers are registered below.

func (*Route) OptionsFunc

func (r *Route) OptionsFunc(f http.HandlerFunc) *Route

OptionsFunc adds a plain function as a handler for OPTIONS methods to this route. This handler will also be called for any routes further down the path from this point if no other OPTIONS handlers are registered below.

func (*Route) Patch

func (r *Route) Patch(handler http.Handler) *Route

Patch adds a handler for PATCH methods to this route.

func (*Route) PatchFunc

func (r *Route) PatchFunc(f http.HandlerFunc) *Route

PatchFunc adds a plain function as a handler for PATCH methods to this route.

func (*Route) Post

func (r *Route) Post(handler http.Handler) *Route

Post adds a handler for POST methods to this route.

func (*Route) PostFunc

func (r *Route) PostFunc(f http.HandlerFunc) *Route

PostFunc adds a plain function as a handler for POST methods to this route.

func (*Route) Put

func (r *Route) Put(handler http.Handler) *Route

Put adds a handler for PUT methods to this route.

func (*Route) PutFunc

func (r *Route) PutFunc(f http.HandlerFunc) *Route

PutFunc adds a plain function as a handler for PUT methods to this route.

func (*Route) Redirect

func (r *Route) Redirect(url string, permanent bool) *Route

Redirect adds a redirect handler for ANY method for this route.

Redirects use either http.StatusPermanentRedirect or http.StatusTemporaryRedirect as their code.

func (*Route) Route

func (r *Route) Route(path string) *Route

Route walks down the route tree following pattern and returns either a new or previously existing node that represents that specific path.

type ServeMux

type ServeMux struct {
	// contains filtered or unexported fields
}

ServeMux is the multiplexer for http requests

func NewServeMux

func NewServeMux() *ServeMux

NewServeMux creates a new multiplexer, and sets up a default not found handler

func (*ServeMux) Handle

func (s *ServeMux) Handle(path string, handler http.Handler)

Handle registers the handler for the given pattern. If a handler already exists for pattern it is overwritten.

func (*ServeMux) HandleFunc

func (s *ServeMux) HandleFunc(path string, handler func(http.ResponseWriter, *http.Request))

HandleFunc registers the handler function for the given pattern.

func (*ServeMux) HandleHost

func (s *ServeMux) HandleHost(host, path string, handler http.Handler)

HandleHost registers the handler for the given pattern and host. If a handler already exists for pattern it is overwritten.

func (*ServeMux) Handler

func (s *ServeMux) Handler(r *http.Request) (http.Handler, string)

Handler returns the handler to use for the given request, consulting r.Method, r.Host, and r.URL.Path. It always returns a non-nil handler. If the path is not in its canonical form, the handler will be an internally-generated handler that redirects to the canonical path.

Handler also returns the registered pattern that matches the request or, in the case of internally-generated redirects, the pattern that will match after following the redirect.

If there is no registered handler that applies to the request, Handler returns a “page not found” handler and an empty pattern.

func (*ServeMux) HandlerAndMiddleware

func (s *ServeMux) HandlerAndMiddleware(r *http.Request) (http.Handler, []Middleware, string)

HandlerAndMiddleware returns the same as Handler, but with the addition of an array of middleware, in the order they would have been executed

func (*ServeMux) Middleware

func (s *ServeMux) Middleware(path string, middleware Middleware)

Middleware adds middleware for the given pattern.

func (*ServeMux) MiddlewareExceptFor added in v1.1.0

func (s *ServeMux) MiddlewareExceptFor(path string, middleware Middleware, verbs ...string)

MiddlewareExceptFor adds a middleware to this node, but will only be executed for requests that are not in the list of verbs. Verbs are case sensitive, and should use the `http.Method*` constants. Panics if any of the verbs provided are unknown.

func (*ServeMux) MiddlewareFor added in v1.1.0

func (s *ServeMux) MiddlewareFor(path string, middleware Middleware, verbs ...string)

MiddlewareFor adds a middleware to this node, but will only be executed for requests with the verb specified. Verbs are case sensitive, and should use the `http.Method*` constants. Panics if any of the verbs provided are unknown.

func (*ServeMux) MiddlewareFunc

func (s *ServeMux) MiddlewareFunc(path string, m MiddlewareFunc) *Route

MiddlewareFunc registers a plain function as a middleware.

func (*ServeMux) MiddlewareHost

func (s *ServeMux) MiddlewareHost(host, path string, middleware Middleware)

MiddlewareHost adds middleware for the given pattern.

func (*ServeMux) NotFound

func (s *ServeMux) NotFound(handler http.Handler)

NotFound sets the default not found handler for the server

func (*ServeMux) Route

func (s *ServeMux) Route(path string) *Route

Route returns the route from the root of the domain to the given pattern

func (*ServeMux) RouteHost

func (s *ServeMux) RouteHost(host, path string) *Route

RouteHost returns the route from the root of the domain to the given pattern on a specific domain

func (*ServeMux) ServeHTTP

func (s *ServeMux) ServeHTTP(rw http.ResponseWriter, req *http.Request)

ServeHTTP dispatches the request to the handler whose pattern most closely matches the request URL.

func (*ServeMux) String

func (s *ServeMux) String() string

String returns a list of all routes registered with this server

Directories

Path Synopsis
example module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL