livery_router (livery v0.2.0)

View Source

Radix-style path-segment router.

Routes are compiled into an immutable trie. Each segment of a pattern is one of:

  • static, e.g. users in /users/new;
  • parameter, prefixed with :, e.g. :id in /users/:id;
  • wildcard, prefixed with *, e.g. *path in /files/*path, matching all remaining segments joined back with /.

match/3 returns {ok, Handler, Bindings, Meta} on a method-aware hit, {error, {method_not_allowed, Methods}} when the path matches but no route is registered for the requested method, or {error, not_found} otherwise.

Routers compose: merge/2 stitches two together, nest/3 mounts a sub-router under a path prefix, layer/2 wraps one in a middleware stack, and routes/1 reconstructs the flat route list from any router.

Summary

Functions

Build a router from a list of routes in one shot.

Wrap every route of a router with a middleware stack.

Look up a route by method and path.

Combine routers into one. On a duplicate Method+Pattern, the later router wins.

Merge two routers. R2 wins on a duplicate Method+Pattern.

Mount a sub-router under a path prefix.

Mount Sub under Prefix into Parent (merge(Parent, nest(Prefix, Sub))).

Empty router with no routes.

Reconstruct the route list a router was built from.

Types

bindings()

-type bindings() :: #{binary() => binary()}.

handler()

-type handler() :: term().

meta()

-type meta() :: term().

method()

-type method() :: binary() | '_'.

pattern()

-type pattern() :: binary().

route()

-type route() :: {method(), pattern(), handler()} | {method(), pattern(), handler(), meta()}.

router()

-opaque router()

Functions

add(Method, Pattern, Handler, Meta, Router)

-spec add(method(), pattern(), handler(), meta(), router()) -> router().

Insert one route.

Method may be '_' to match any HTTP method. Later additions with the same Method+Pattern replace the previous entry.

compile(Routes)

-spec compile([{method(), pattern(), handler()} | {method(), pattern(), handler(), meta()}]) -> router().

Build a router from a list of routes in one shot.

layer(Stack, Router)

-spec layer(livery_middleware:stack(), router()) -> router().

Wrap every route of a router with a middleware stack.

Stack is prepended to each route's Meta's middleware (so it runs outside the route's own middleware). Use it to put one stack, say auth, over a whole mounted subtree: nest(Prefix, layer(Stack, Sub), Parent).

match(Method, Path, Router)

-spec match(method(), binary(), router()) ->
               {ok, handler(), bindings(), meta()} |
               {error, not_found} |
               {error, {method_not_allowed, [method()]}}.

Look up a route by method and path.

merge(Routers)

-spec merge([router()]) -> router().

Combine routers into one. On a duplicate Method+Pattern, the later router wins.

merge(R1, R2)

-spec merge(router(), router()) -> router().

Merge two routers. R2 wins on a duplicate Method+Pattern.

nest(Prefix, Sub)

-spec nest(pattern(), router()) -> router().

Mount a sub-router under a path prefix.

Every route of Sub is re-registered with Prefix prepended to its pattern. A wildcard sub-route stays last under the prefix, so mounting a static router keeps *path valid.

nest(Prefix, Sub, Parent)

-spec nest(pattern(), router(), router()) -> router().

Mount Sub under Prefix into Parent (merge(Parent, nest(Prefix, Sub))).

new()

-spec new() -> router().

Empty router with no routes.

routes(Router)

-spec routes(router()) -> [{method(), pattern(), handler(), meta()}].

Reconstruct the route list a router was built from.

Returns one {Method, Pattern, Handler, Meta} per registered handler. The inverse of compile/1: compile(routes(R)) matches the same paths as R. Handy for feeding a router (including a composed one) to livery_openapi:build/1, which takes a route list.