reitit/doc/interceptors.md

78 lines
3.4 KiB
Markdown
Raw Normal View History

2018-02-11 17:15:25 +00:00
# Interceptors (WIP)
2018-02-02 12:48:28 +00:00
2018-08-22 18:55:03 +00:00
Reitit also support for [Pedestal](pedestal.io)-style [interceptors](http://pedestal.io/reference/interceptors) as an alternative to Middleware. Basic interceptor handling is implemented in `reitit.interceptor` package. There is no interceptor executor shipped, but you can use libraries like [Pedestal Interceptor](https://github.com/pedestal/pedestal/tree/master/interceptor) or [Sieppari](https://github.com/metosin/sieppari) to execute the chains.
2018-02-02 12:48:28 +00:00
2018-08-22 17:24:17 +00:00
## Reitit-http
2018-02-11 17:15:25 +00:00
2018-08-22 17:24:17 +00:00
An alternative to `reitit-ring`, using interceptors instead of middleware. Currently not finalized, you can track progress in [here](https://github.com/metosin/reitit/pull/124).
2018-02-11 17:15:25 +00:00
2018-08-22 17:24:17 +00:00
## Examples
2018-02-02 12:48:28 +00:00
2018-08-22 18:55:03 +00:00
### Standalone
2018-08-22 17:24:17 +00:00
2018-08-22 18:55:03 +00:00
* [Sieppari](https://github.com/metosin/sieppari) for executing the chain
* [Manifold](https://github.com/ztellman/manifold) for async
* [data-specs](https://github.com/metosin/spec-tools/blob/master/README.md#data-specs) for coercion
2018-02-02 12:48:28 +00:00
```clj
2018-08-22 17:24:17 +00:00
(require '[reitit.interceptor.sieppari :as sieppari])
(require '[reitit.http.coercion :as coercion])
2018-02-02 12:48:28 +00:00
(require '[reitit.http :as http])
2018-08-22 17:24:17 +00:00
(require '[reitit.ring :as ring])
2018-02-02 12:48:28 +00:00
(require '[reitit.coercion.spec])
(require '[clojure.set :as set])
2018-08-22 17:24:17 +00:00
(require '[manifold.deferred :as d])
(require '[ring.adapter.jetty :as jetty])
2018-02-02 12:48:28 +00:00
(def auth-interceptor
"Interceptor that mounts itself if route has `:roles` data. Expects `:roles`
to be a set of keyword and the context to have `[:user :roles]` with user roles.
responds with HTTP 403 if user doesn't have the roles defined, otherwise no-op."
{:name ::auth
:compile (fn [{:keys [roles]} _]
(if (seq roles)
{:description (str "requires roles " roles)
:spec {:roles #{keyword?}}
:context-spec {:user {:roles #{keyword}}}
:enter (fn [{{user-roles :roles} :user :as ctx}]
(if (not (set/subset? roles user-roles))
(assoc ctx :response {:status 403, :body "forbidden"})
2018-08-22 17:24:17 +00:00
ctx))}))})
(def async-interceptor
{:enter (fn [ctx] (d/future ctx))})
2018-02-02 12:48:28 +00:00
(def app
2018-08-22 17:24:17 +00:00
(http/ring-handler
2018-02-02 12:48:28 +00:00
(http/router
2018-08-22 17:24:17 +00:00
["/api" {:interceptors [async-interceptor auth-interceptor]}
2018-02-02 12:48:28 +00:00
["/ping" {:name ::ping
:get (constantly
{:status 200
:body "pong"})}]
["/plus/:z" {:name ::plus
:post {:parameters {:query {:x int?}
:body {:y int?}
:path {:z int?}}
:responses {200 {:body {:total pos-int?}}}
:roles #{:admin}
:handler (fn [{:keys [parameters]}]
(let [total (+ (-> parameters :query :x)
(-> parameters :body :y)
(-> parameters :path :z))]
{:status 200
:body {:total total}}))}}]]
{:data {:coercion reitit.coercion.spec/coercion
2018-08-22 17:24:17 +00:00
:interceptors [coercion/coerce-exceptions-interceptor
coercion/coerce-request-interceptor
coercion/coerce-response-interceptor]}})
(ring/create-default-handler)
{:executor sieppari/executor}))
(jetty/run-jetty #'app {:port 3000, :join? false, :async? true})
2018-02-02 12:48:28 +00:00
```
2018-08-22 18:55:03 +00:00
### Pedestal
**TODO**