The request-time half: decide, rewrite, and restore.
Kept out of the use DynamicRoutes macro so that what gets injected into a
host router is three lines rather than an implementation. A bug fixed here
is fixed by upgrading the dependency, not by recompiling somebody's router.
Summary
Functions
Whether this request was routed dynamically rather than by a declared route.
The path segments the internal catch-all route was registered under.
Decides what should happen to a request.
What the resolver returned for this request, or nil.
Puts the client's own path back on a rewritten conn.
Functions
@spec dynamic?(Plug.Conn.t()) :: boolean()
Whether this request was routed dynamically rather than by a declared route.
The path segments the internal catch-all route was registered under.
Read back from the router's own route table rather than assumed, so that
declaring it inside a scope — scope "/admin" — still works: the rewrite
has to produce whatever path the route actually ended up at, not the one
that was configured before the scope was applied.
@spec prepare(Plug.Conn.t(), module(), module()) :: {:rewrite, Plug.Conn.t()} | :pass
Decides what should happen to a request.
Returns {:rewrite, conn} with a conn whose path points at the internal
route, or :pass to let the router handle the request untouched.
The order is the whole point: a path that matches a declared route is passed through before the resolver is consulted at all. That is what makes declaration order stop mattering — a database page can never shadow a route in the router, whichever was written first, because the router is asked first and only its misses go any further.
@spec resolution(Plug.Conn.t()) :: term() | nil
What the resolver returned for this request, or nil.
@spec restore_path(Plug.Conn.t()) :: Plug.Conn.t()
Puts the client's own path back on a rewritten conn.
Called by DynamicRoutes.Dispatcher after the pipeline has run and before
the controller does, so the controller never observes the internal path.