Pedestal represents interceptors, its analog to Ring middleware, as data. Let’s look at how we can use that to conditionally inject a ClojureScript REPL into responses.
Pedestal Terminology
Two working definitions as we start
- Interceptor - a record containing keys corresponding functions for execution stages. Serves an analogous role to middleware in Ring.
- context - a map with all data relating to processing a request. Contains Ring request and response maps along with additional data.
Marking Routes with Metadata
We’ll start by adding metadata indicating that a browser REPL should be included in the response. We can either add it directly to an endpoint
or to an interceptor anywhere else in the chain
Interceptor Application
Interceptors serve a similar role as middlewares in Ring but the implementation is substantially different. See Pedestal’s docs for a full discussion, but for now the important difference is in how middlewares and interceptors are combined. In Ring, middlewares compose functionally
Pedestal represents interceptors sequentially, adding them as a queue to the request / response context
(under :io.pedestal.impl.interceptor/queue
). In broad strokes, requests are processed by taking an interceptor from the queue and applying its :enter
function to the context
, producing a new context
that the next interceptor in the queue will act on. As each interceptor is visited, it’s added to a stack in the context
that will be traversed on the :leave
stage. The code is well worth a read.
Knowing that the other interceptors involved in processing a request are visible in the context’s :io.pedestal.impl.interceptor/queue
, we can write an interceptor that scans the queue looking for the :browser-repl
metadata and injects a repl into the response if it’s found
We use around
to implement browser-repl
so that we can examine the interceptor queue in the before
stage and set a flag in the context
called :include-browser-repl
that we’ll read when a response is present in the leave
phase and decide whether to call inject-repl
.
inject-repl
is a function that handles the mechanics of modifying the response, along the lines of
Note Brian Rowe and Alex Redington suggested a couple of very nice extensions to this idea that I’d recommend studying before implementing it.
Kinda cool, right? Interceptors are data, and neat approaches fall out. We use a similar pattern for authorization.
Also, big thanks to Brian Rowe and Rick Hall for a number of improvements to this post!