Pedestal is data driven, and the routing information starts in one form (as data) and is then
transformed in a couple of stages to reach a final result that can be used to route incoming requests.
The start is the route specification.
Pedestal has three built-in formats for route specification:
table, terse, and verbose. Table is the newest format
and is the preferred format; the others are maintained for compatibility.
For each of the built-in formats, there is a function that can convert that specific format
into a routing fragment. One or more fragments are then combined to form the routing table.
Pedestal will determine which function to invoke based on the kind of data: set, vector, or map:
flowchart
subgraph ExpandableRoutes/-expand-routes
table("#{} table")-->|table/table-routes|expanded
terse("[] terse")-->|terse/terse-routes|expanded
map("{} verbose")-->|terse/map-routes->vec-routes|expanded
end
expanded(routing table)-->
cons(Router Constructor Fn)-->|Routing Function|inter
inter(Routing Interceptor)
Route specifications are the data values that spell out the possible routes.
These are normalized and expanded and combined into a routing table.
A Router Constructor function is passed the routing table, and applies a specific strategy to match incoming requests
to the provided routes; there are a few different constructor functions, each
with different limitations and trade-offs. The constructor returns a Routing function
encapsulating the routing table and the strategy.
The routing function is passed the request and returns a vector of two values on success: the matching route, then the map
of path parameters. On failure, the routing function returns nil.
The routing interceptor combines the routing function and the current request to identify the route, if any,
that matched the request. When routing is succesful, the interceptor updates the
request-map.adoc, and queues up route-specific interceptors to handle the request.
|
There are actually two different implementations of the interceptor; the production one is used
in the normal case, where the routing table is an actual value. During development,
the routing table may be a function that returns the routing table; in which case, the routing
function is rebuilt on every request.
|
Generally, all of this is automatic; an application provides a route specification in the :io.pedestal.http/route key
of the service-map.adoc (and perhaps a value for :io.pedestal.http/router) and a routing
interceptor is automatically created.