|
This is the detailed interceptor reference; if you are new to Pedestal
you may want to start with the guides:what-is-an-interceptor.adoc.
|
Interceptors are the basic unit of work in Pedestal. The
core library provides interceptors that are generally useful for
creating HTTP web services. Applications augment those with their own
logic to handle everything specific the application’s domain.
An interceptor is a Clojure record with four keys:
-
:name
-
:enter
-
:leave
-
:error
The :name key is a keyword, often a namespace-qualified keyword.
The :enter and :leave keys are unary functions.
The :error key is used for error handling.
An interceptor must
provide a :name
and at least one of :enter, :leave and :error.
Each function is called with a context-map.adoc and must return either a context
map or a {core_async} channel that will deliver a context map; the latter case triggers
asynchronous request processing.
Pedestal calls the :enter function on the way "in" to handling a
request. It calls the :leave function on the way back "out". This is
shown here for a single interceptor:
seqdiag {
"Interceptor Chain" -> Interceptor [label=":enter"]
"Interceptor Chain" <- Interceptor
"Interceptor Chain" -> "Other Interceptors"
"Interceptor Chain" <- "Other Interceptors"
"Interceptor Chain" -> Interceptor [label=":leave"]
"Interceptor Chain" <- Interceptor
}
Either the :enter or :leave function may be omitted without harm.
Before executing the interceptor chain, the interceptors are added
to a queue, in the specific order of execution.
During the :enter phase, the next interceptor is popped off the queue,
pushed onto the leave stack, and its :enter function, if any, is executed.
Once the handler (or other interceptor) adds a :response to the context,
the chain logic switches to :leave mode: it pops interceptors off
the leave stack and invokes the :leave function, if any.
Because it’s the leave stack the :leave functions are invoked
in the opposite order from the :enter functions.
seqdiag {
"Interceptor Chain" -> A [label=":enter"]
"Interceptor Chain" <- A
"Interceptor Chain" -> B [label=":enter"]
"Interceptor Chain" <- B
"Interceptor Chain" -> C [label=":enter"]
"Interceptor Chain" <- C
"Interceptor Chain" -> C [label=":leave"]
"Interceptor Chain" <- C
"Interceptor Chain" -> B [label=":leave"]
"Interceptor Chain" <- B
"Interceptor Chain" -> A [label=":leave"]
"Interceptor Chain" <- A
}
Both the queue and the stack reside in the context map. Since
interceptors can modify the context map, that means they can change
the plan of execution for the rest of the request! Interceptors are
allowed to enqueue more interceptors to be called, or they can
terminate the request.
This process, of running all the interceptor :enter functions, then running
the interceptor :leave functions, is called executing the interceptor chain.