More controllable composition of Ring middlewares.
This library is attempt to resolve following difficulties with usage of Ring middlewares:
- Unclear middleware responsibility, if they handle request, response or both.
- No hints for middleware dependencies, when one middleware works only after another.
- Inverted order when written with
->
macro what makes hard to reason about actual request/response flow between wrappers.
Ring handlers are build from handler function and sequence of middleware configurations using handler/build function.
Default type of ring handler is sync handler. To produce async ring handler
use either :async
option or {:async true}
in handler's meta.
Every middleware configuration is a map with keys:
-
{:keys [wrap]}
:wrap
– a function(fn [handler] new-handler)
to wrap handler.
-
{:keys [enter leave]}
:enter
— a function(fn [request] new-request)
to transform request.:leave
– a function(fn [response request] new-response)
to transform response.
Maps with :wrap
and :enter
/:leave
causes exception.
Only middlewares with :wrap
can short-circuit, :enter
/:leave
just modify
request/response.
The middlewares are applied in the order:
- Request flows from first to last.
- Response flows from last to first.
- Every middleware receives request from previous
:wrap
/:enter
middlewares only. - Every
:leave
/:wrap
receives response from next middlewares.
See also walkthrough.
The ring-middleware namespace contains configuration for middlewares in ring libraries.
The libraries should be added in project dependencies explicitly for configuration to be used.
An implementation of the ring-defaults using ring-control configurations: