reitit-sieppari & small fixes

This commit is contained in:
Tommi Reiman 2018-08-19 22:56:54 +03:00
parent 91473c5976
commit c1a747857f
10 changed files with 118 additions and 62 deletions

View file

@ -19,6 +19,7 @@ See the [full documentation](https://metosin.github.io/reitit/) for details.
## Modules ## Modules
* `reitit` - all bundled
* `reitit-core` - the routing core * `reitit-core` - the routing core
* `reitit-ring` - a [ring router](https://metosin.github.io/reitit/ring/ring.html) * `reitit-ring` - a [ring router](https://metosin.github.io/reitit/ring/ring.html)
* `reitit-middleware` - [common data-driven middleware](https://metosin.github.io/reitit/ring/default_middleware.html) for `reitit-ring` * `reitit-middleware` - [common data-driven middleware](https://metosin.github.io/reitit/ring/default_middleware.html) for `reitit-ring`
@ -26,11 +27,12 @@ See the [full documentation](https://metosin.github.io/reitit/) for details.
* `reitit-schema` [Schema](https://github.com/plumatic/schema) coercion * `reitit-schema` [Schema](https://github.com/plumatic/schema) coercion
* `reitit-swagger` [Swagger2](https://swagger.io/) apidocs * `reitit-swagger` [Swagger2](https://swagger.io/) apidocs
* `reitit-swagger-ui` Integrated [Swagger UI](https://github.com/swagger-api/swagger-ui) * `reitit-swagger-ui` Integrated [Swagger UI](https://github.com/swagger-api/swagger-ui)
* [`reitit-frontend`](frontend/basics.md) Tools for frontend routing.
Bubblin' under: Bubblin' under:
* `reitit-http` with enchanced Pedestal-style Interceptors (WIP) * `reitit-http` http-routing with Pedestal-style Interceptors (WIP)
* `reitit-frontend` with Keechma-style Controllers (WIP) * `reitit-sieppari` support for [Sieppari](https://github.com/metosin/sieppari) Interceptors (WIP)
## Latest version ## Latest version
@ -60,8 +62,9 @@ Optionally, the parts can be required separately:
;; frontend helpers (alpha) ;; frontend helpers (alpha)
[metosin/reitit-frontend "0.2.0-SNAPSHOT"] [metosin/reitit-frontend "0.2.0-SNAPSHOT"]
;; http helpers (alpha) ;; http with interceptors (alpha)
[metosin/reitit-http "0.2.0-SNAPSHOT"] [metosin/reitit-http "0.2.0-SNAPSHOT"]
[metosin/reitit-sieppari "0.2.0-SNAPSHOT"]
``` ```
## Quick start ## Quick start

View file

@ -13,15 +13,24 @@
Modules: Modules:
* `reitit` - all bundled
* `reitit-core` - the routing core * `reitit-core` - the routing core
* [`reitit-ring`](ring/ring.md) with [data-driven middleware](https://metosin.github.io/reitit/ring/data_driven_middleware.html) * `reitit-ring` - a [ring router](https://metosin.github.io/reitit/ring/ring.html)
* `reitit-middleware` - [common data-driven middleware](https://metosin.github.io/reitit/ring/default_middleware.html) for `reitit-ring`
* `reitit-spec` [clojure.spec](https://clojure.org/about/spec) coercion * `reitit-spec` [clojure.spec](https://clojure.org/about/spec) coercion
* `reitit-schema` [Schema](https://github.com/plumatic/schema) coercion * `reitit-schema` [Schema](https://github.com/plumatic/schema) coercion
* `reitit-swagger` [Swagger2](https://swagger.io/) apidocs * `reitit-swagger` [Swagger2](https://swagger.io/) apidocs
* `reitit-swagger-ui` Integrated [Swagger UI](https://github.com/swagger-api/swagger-ui). * `reitit-swagger-ui` Integrated [Swagger UI](https://github.com/swagger-api/swagger-ui).
* [`reitit-frontend`](frontend/basics.md) Tools for frontend routing. * [`reitit-frontend`](frontend/basics.md) Tools for frontend routing.
To use Reitit, add the following dependency to your project: Bubblin' under:
* `reitit-http` http-routing with Pedestal-style Interceptors (WIP)
* `reitit-sieppari` support for [Sieppari](https://github.com/metosin/sieppari) Interceptors (WIP)
## Latest version
All bundled:
```clj ```clj
[metosin/reitit "0.2.0-SNAPSHOT"] [metosin/reitit "0.2.0-SNAPSHOT"]
@ -47,8 +56,9 @@ Optionally, the parts can be required separately:
;; frontend helpers (alpha) ;; frontend helpers (alpha)
[metosin/reitit-frontend "0.2.0-SNAPSHOT"] [metosin/reitit-frontend "0.2.0-SNAPSHOT"]
;; http helpers (alpha) ;; http with interceptors (alpha)
[metosin/reitit-http "0.2.0-SNAPSHOT"] [metosin/reitit-http "0.2.0-SNAPSHOT"]
[metosin/reitit-sieppari "0.2.0-SNAPSHOT"]
``` ```
For discussions, there is a [#reitit](https://clojurians.slack.com/messages/reitit/) channel in [Clojurians slack](http://clojurians.net/). For discussions, there is a [#reitit](https://clojurians.slack.com/messages/reitit/) channel in [Clojurians slack](http://clojurians.net/).

View file

@ -7,10 +7,19 @@
(defprotocol IntoInterceptor (defprotocol IntoInterceptor
(into-interceptor [this data opts])) (into-interceptor [this data opts]))
(defrecord Interceptor [name handler? enter leave error]) (defrecord Interceptor [name enter leave error])
(defrecord Endpoint [data interceptors]) (defrecord Endpoint [data interceptors queue])
(defrecord Context [request response exception]) (defrecord Context [request response exception])
(defprotocol Executor
(queue
[this interceptors]
"takes a sequence of interceptors and compiles them to queue for the executor")
(execute
[this interceptors request]
[this interceptors request respond raise]
"executes the interceptor chain"))
(defn context [request] (defn context [request]
(map->Context {:request request})) (map->Context {:request request}))
@ -50,7 +59,7 @@
:cljs function) :cljs function)
(into-interceptor [this data opts] (into-interceptor [this data opts]
(into-interceptor (into-interceptor
{:handler? true {:name ::handler
:enter (fn [ctx] :enter (fn [ctx]
(assoc ctx :response (this (:request ctx))))} (assoc ctx :response (this (:request ctx))))}
data opts)) data opts))
@ -106,10 +115,12 @@
(defn compile-result (defn compile-result
([route opts] ([route opts]
(compile-result route opts nil)) (compile-result route opts nil))
([[_ {:keys [interceptors handler] :as data}] opts _] ([[_ {:keys [interceptors handler] :as data}] {:keys [::queue] :as opts} _]
(map->Endpoint (let [chain (chain (into (vec interceptors) [handler]) data opts)]
{:interceptors (chain (into (vec interceptors) [handler]) data opts) (map->Endpoint
:data data}))) {:interceptors chain
:queue ((or queue identity) chain)
:data data}))))
(defn router (defn router
"Creates a [[reitit.core/Router]] from raw route data and optionally an options map with "Creates a [[reitit.core/Router]] from raw route data and optionally an options map with

View file

@ -5,16 +5,7 @@
[reitit.core :as r] [reitit.core :as r]
[reitit.impl :as impl])) [reitit.impl :as impl]))
(defrecord Endpoint [data handler path method interceptors queue]) (defrecord Endpoint [data interceptors queue handler path method])
(defprotocol Executor
(queue
[this interceptors]
"takes a sequence of interceptors and compiles them to queue for the executor")
(execute
[this request interceptors]
[this request interceptors respond raise]
"executes the interceptor chain"))
(defn coerce-handler [[path data] {:keys [expand] :as opts}] (defn coerce-handler [[path data] {:keys [expand] :as opts}]
[path (reduce [path (reduce
@ -23,23 +14,16 @@
(update acc method expand opts) (update acc method expand opts)
acc)) data ring/http-methods)]) acc)) data ring/http-methods)])
(defn compile-result [[path data] {:keys [::queue] :as opts}] (defn compile-result [[path data] opts]
(let [[top childs] (ring/group-keys data) (let [[top childs] (ring/group-keys data)
->handler (fn [handler]
(if handler
(fn [ctx]
(->> ctx :request handler (assoc ctx :response)))))
compile (fn [[path data] opts scope] compile (fn [[path data] opts scope]
(let [data (update data :handler ->handler)] (interceptor/compile-result [path data] opts scope))
(interceptor/compile-result [path data] opts scope)))
->endpoint (fn [p d m s] ->endpoint (fn [p d m s]
(let [compiled (compile [p d] opts s) (let [compiled (compile [p d] opts s)]
interceptors (:interceptors compiled)]
(-> compiled (-> compiled
(map->Endpoint) (map->Endpoint)
(assoc :path p) (assoc :path p)
(assoc :method m) (assoc :method m))))
(assoc :queue ((or queue identity) interceptors)))))
->methods (fn [any? data] ->methods (fn [any? data]
(reduce (reduce
(fn [acc method] (fn [acc method]
@ -83,41 +67,44 @@
| key | description | | key | description |
| ----------------|-------------| | ----------------|-------------|
| `:executor` | [[Executor]] for the interceptor chain | `:executor` | `reitit.interceptor.Executor` for the interceptor chain
| `:interceptors` | Optional sequence of interceptors that are always run before any other interceptors, even for the default handler" | `:interceptors` | Optional sequence of interceptors that are always run before any other interceptors, even for the default handler"
[router default-handler {:keys [executor interceptors]}] [router default-handler {:keys [executor interceptors]}]
(let [default-handler (or default-handler (fn ([_]) ([_ respond _] (respond nil)))) (let [default-handler (or default-handler (fn ([_]) ([_ respond _] (respond nil))))
default-queue (queue executor (interceptor/into-interceptor (concat interceptors [default-handler]) nil (r/options router))) default-queue (->> [default-handler]
(concat interceptors)
(map #(interceptor/into-interceptor % nil (r/options router)))
(interceptor/queue executor))
router-opts (-> (r/options router) router-opts (-> (r/options router)
(assoc ::queue (partial queue executor)) (assoc ::interceptor/queue (partial interceptor/queue executor))
(update :interceptors (partial concat interceptors))) (update-in [:data :interceptors] (partial into (vec interceptors))))
router (router (r/routes router) router-opts)] router (reitit.http/router (r/routes router) router-opts)]
(with-meta (with-meta
(fn (fn
([request] ([request]
(if-let [match (r/match-by-path router (:uri request))] (if-let [match (r/match-by-path router (:uri request))]
(let [method (:request-method request) (let [method (:request-method request)
path-params (:path-params match) path-params (:path-params match)
result (:result match) endpoint (-> match :result method)
interceptors (-> result method :interceptors) interceptors (or (:queue endpoint) (:interceptors endpoint))
request (-> request request (-> request
(impl/fast-assoc :path-params path-params) (impl/fast-assoc :path-params path-params)
(impl/fast-assoc ::r/match match) (impl/fast-assoc ::r/match match)
(impl/fast-assoc ::r/router router))] (impl/fast-assoc ::r/router router))]
(execute executor interceptors request)) (interceptor/execute executor interceptors request))
(execute executor default-queue request))) (interceptor/execute executor default-queue request)))
([request respond raise] ([request respond raise]
(if-let [match (r/match-by-path router (:uri request))] (if-let [match (r/match-by-path router (:uri request))]
(let [method (:request-method request) (let [method (:request-method request)
path-params (:path-params match) path-params (:path-params match)
result (:result match) endpoint (-> match :result method)
interceptors (-> result method :interceptors) interceptors (or (:queue endpoint) (:interceptors endpoint))
request (-> request request (-> request
(impl/fast-assoc :path-params path-params) (impl/fast-assoc :path-params path-params)
(impl/fast-assoc ::r/match match) (impl/fast-assoc ::r/match match)
(impl/fast-assoc ::r/router router))] (impl/fast-assoc ::r/router router))]
(execute executor interceptors request respond raise)) (interceptor/execute executor interceptors request respond raise))
(execute executor default-queue request respond raise)) (interceptor/execute executor default-queue request respond raise))
nil)) nil))
{::r/router router}))) {::r/router router})))

View file

@ -0,0 +1,10 @@
(defproject metosin/reitit-sieppari "0.2.0-SNAPSHOT"
:description "Reitit: Sieppari Interceptors"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:plugins [[lein-parent "0.3.2"]]
:parent-project {:path "../../project.clj"
:inherit [:deploy-repositories :managed-dependencies]}
:dependencies [[metosin/reitit-core]
[metosin/sieppari]])

View file

@ -0,0 +1,14 @@
(ns reitit.interceptor.sieppari
(:require [reitit.interceptor :as interceptor]
[sieppari.queue :as queue]
[sieppari.core :as sieppari]))
(def executor
(reify
interceptor/Executor
(queue [_ interceptors]
(queue/into-queue interceptors))
(execute [_ interceptors request]
(sieppari/execute interceptors request))
(execute [_ interceptors request respond raise]
(sieppari/execute interceptors request respond raise))))

View file

@ -14,4 +14,5 @@
[metosin/reitit-http] [metosin/reitit-http]
[metosin/reitit-swagger] [metosin/reitit-swagger]
[metosin/reitit-swagger-ui] [metosin/reitit-swagger-ui]
[metosin/reitit-frontend]]) [metosin/reitit-frontend]
[metosin/reitit-sieppari]])

View file

@ -19,13 +19,15 @@
[metosin/reitit-swagger "0.2.0-SNAPSHOT"] [metosin/reitit-swagger "0.2.0-SNAPSHOT"]
[metosin/reitit-swagger-ui "0.2.0-SNAPSHOT"] [metosin/reitit-swagger-ui "0.2.0-SNAPSHOT"]
[metosin/reitit-frontend "0.2.0-SNAPSHOT"] [metosin/reitit-frontend "0.2.0-SNAPSHOT"]
[metosin/reitit-sieppari "0.2.0-SNAPSHOT"]
[meta-merge "1.0.0"] [meta-merge "1.0.0"]
[ring/ring-core "1.6.3"] [ring/ring-core "1.6.3"]
[metosin/spec-tools "0.7.1"] [metosin/spec-tools "0.7.1"]
[metosin/schema-tools "0.10.3"] [metosin/schema-tools "0.10.3"]
[metosin/ring-swagger-ui "2.2.10"] [metosin/ring-swagger-ui "2.2.10"]
[metosin/muuntaja "0.6.0-alpha1"] [metosin/muuntaja "0.6.0-alpha1"]
[metosin/jsonista "0.2.1"]] [metosin/jsonista "0.2.1"]
[metosin/sieppari "0.0.0-alpha1"]]
:plugins [[jonase/eastwood "0.2.6"] :plugins [[jonase/eastwood "0.2.6"]
[lein-doo "0.1.10"] [lein-doo "0.1.10"]
@ -46,7 +48,8 @@
"modules/reitit-schema/src" "modules/reitit-schema/src"
"modules/reitit-swagger/src" "modules/reitit-swagger/src"
"modules/reitit-swagger-ui/src" "modules/reitit-swagger-ui/src"
"modules/reitit-frontend/src"] "modules/reitit-frontend/src"
"modules/reitit-sieppari/src"]
:dependencies [[org.clojure/clojure "1.9.0"] :dependencies [[org.clojure/clojure "1.9.0"]
[org.clojure/clojurescript "1.10.339"] [org.clojure/clojurescript "1.10.339"]
@ -61,6 +64,7 @@
[ikitommi/immutant-web "3.0.0-alpha1"] [ikitommi/immutant-web "3.0.0-alpha1"]
[metosin/muuntaja "0.6.0-alpha1"] [metosin/muuntaja "0.6.0-alpha1"]
[metosin/ring-swagger-ui "2.2.10"] [metosin/ring-swagger-ui "2.2.10"]
[metosin/sieppari "0.0.0-alpha1"]
[metosin/jsonista "0.2.1"] [metosin/jsonista "0.2.1"]
[criterium "0.4.4"] [criterium "0.4.4"]

View file

@ -3,6 +3,17 @@
set -e set -e
# Modules # Modules
for ext in reitit-core reitit-spec reitit-schema reitit-ring reitit-middleware reitit-http reitit-swagger reitit-swagger-ui reitit-frontend reitit; do for ext in \
reitit-core \
reitit-spec \
reitit-schema \
reitit-ring \
reitit-middleware \
reitit-http \
reitit-swagger \
reitit-swagger-ui \
reitit-frontend \
reitit-sieppari \
reitit; do
cd modules/$ext; lein "$@"; cd ../..; cd modules/$ext; lein "$@"; cd ../..;
done done

View file

@ -182,18 +182,20 @@
(is (= [::enter_i1 ::enter_i3 :ok ::leave_i3 ::leave_i1] (app "/api"))) (is (= [::enter_i1 ::enter_i3 :ok ::leave_i3 ::leave_i1] (app "/api")))
(testing "routes contain list of actually applied interceptors" (testing "routes contain list of actually applied interceptors"
(is (= [::i1 ::i3 nil] (->> (r/compiled-routes router) (is (= [::i1 ::i3 ::interceptor/handler]
first (->> (r/compiled-routes router)
last first
:interceptors last
(map :name))))) :interceptors
(map :name)))))
(testing "match contains list of actually applied interceptors" (testing "match contains list of actually applied interceptors"
(is (= [::i1 ::i3 nil] (->> "/api" (is (= [::i1 ::i3 ::interceptor/handler]
(r/match-by-path router) (->> "/api"
:result (r/match-by-path router)
:interceptors :result
(map :name)))))))))) :interceptors
(map :name))))))))))
(deftest chain-test (deftest chain-test
(testing "chain can produce interceptor chain of any IntoInterceptor" (testing "chain can produce interceptor chain of any IntoInterceptor"
@ -227,7 +229,10 @@
(is (= [::olipa ::kerran ::avaruus :ok] (app "/ping"))))) (is (= [::olipa ::kerran ::avaruus :ok] (app "/ping")))))
(testing "interceptors can be re-ordered" (testing "interceptors can be re-ordered"
(let [app (create {::interceptor/transform (partial sort-by (juxt :handler? :name))})] (let [app (create {::interceptor/transform (fn [interceptors]
(concat
(sort-by :name (butlast interceptors))
[(last interceptors)]))})]
(is (= [::avaruus ::kerran ::olipa :ok] (app "/ping"))))) (is (= [::avaruus ::kerran ::olipa :ok] (app "/ping")))))
(testing "adding debug interceptor between interceptors" (testing "adding debug interceptor between interceptors"