mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 00:11:11 +00:00
Remove middleware/create & polish stuff
This commit is contained in:
parent
aab842af49
commit
927d4d4389
3 changed files with 121 additions and 113 deletions
|
|
@ -9,13 +9,6 @@
|
||||||
(defrecord Middleware [name wrap])
|
(defrecord Middleware [name wrap])
|
||||||
(defrecord Endpoint [data handler middleware])
|
(defrecord Endpoint [data handler middleware])
|
||||||
|
|
||||||
(defn create [{:keys [wrap compile] :as m}]
|
|
||||||
(when (and wrap compile)
|
|
||||||
(throw
|
|
||||||
(ex-info
|
|
||||||
(str "Middleware can't have both :wrap and :compile defined " m) m)))
|
|
||||||
(map->Middleware m))
|
|
||||||
|
|
||||||
(def ^:dynamic *max-compile-depth* 10)
|
(def ^:dynamic *max-compile-depth* 10)
|
||||||
|
|
||||||
(extend-protocol IntoMiddleware
|
(extend-protocol IntoMiddleware
|
||||||
|
|
@ -35,12 +28,12 @@
|
||||||
#?(:clj clojure.lang.PersistentArrayMap
|
#?(:clj clojure.lang.PersistentArrayMap
|
||||||
:cljs cljs.core.PersistentArrayMap)
|
:cljs cljs.core.PersistentArrayMap)
|
||||||
(into-middleware [this data opts]
|
(into-middleware [this data opts]
|
||||||
(into-middleware (create this) data opts))
|
(into-middleware (map->Middleware this) data opts))
|
||||||
|
|
||||||
#?(:clj clojure.lang.PersistentHashMap
|
#?(:clj clojure.lang.PersistentHashMap
|
||||||
:cljs cljs.core.PersistentHashMap)
|
:cljs cljs.core.PersistentHashMap)
|
||||||
(into-middleware [this data opts]
|
(into-middleware [this data opts]
|
||||||
(into-middleware (create this) data opts))
|
(into-middleware (map->Middleware this) data opts))
|
||||||
|
|
||||||
Middleware
|
Middleware
|
||||||
(into-middleware [{:keys [compile] :as this} data opts]
|
(into-middleware [{:keys [compile] :as this} data opts]
|
||||||
|
|
@ -56,7 +49,7 @@
|
||||||
(if-let [middeware (into-middleware (compile data opts) data opts)]
|
(if-let [middeware (into-middleware (compile data opts) data opts)]
|
||||||
(map->Middleware
|
(map->Middleware
|
||||||
(merge
|
(merge
|
||||||
(dissoc this :create)
|
(dissoc this :compile)
|
||||||
(impl/strip-nils middeware)))))))
|
(impl/strip-nils middeware)))))))
|
||||||
|
|
||||||
nil
|
nil
|
||||||
|
|
@ -70,21 +63,38 @@
|
||||||
(merge {:path path, :data data}
|
(merge {:path path, :data data}
|
||||||
(if scope {:scope scope}))))))
|
(if scope {:scope scope}))))))
|
||||||
|
|
||||||
(defn expand [middleware data opts]
|
(defn- expand-and-transform
|
||||||
|
[middleware data {:keys [::transform] :or {transform identity} :as opts}]
|
||||||
(->> middleware
|
(->> middleware
|
||||||
|
(keep #(into-middleware % data opts))
|
||||||
|
(into [])
|
||||||
|
(transform)
|
||||||
(keep #(into-middleware % data opts))
|
(keep #(into-middleware % data opts))
|
||||||
(into [])))
|
(into [])))
|
||||||
|
|
||||||
(defn compile-handler [middleware handler]
|
(defn- compile-handler [middleware handler]
|
||||||
((apply comp identity (keep :wrap middleware)) handler))
|
((apply comp identity (keep :wrap middleware)) handler))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; public api
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defn chain
|
||||||
|
"Creates a Ring middleware chain out of sequence of IntoMiddleware
|
||||||
|
and Handler. Optional takes route data and (Router) opts."
|
||||||
|
([middleware handler]
|
||||||
|
(chain middleware handler nil))
|
||||||
|
([middleware handler data]
|
||||||
|
(chain middleware handler data nil))
|
||||||
|
([middleware handler data opts]
|
||||||
|
(compile-handler (expand-and-transform middleware data opts) handler)))
|
||||||
|
|
||||||
(defn compile-result
|
(defn compile-result
|
||||||
([route opts]
|
([route opts]
|
||||||
(compile-result route opts nil))
|
(compile-result route opts nil))
|
||||||
([[path {:keys [middleware handler] :as data}]
|
([[path {:keys [middleware handler] :as data}] opts scope]
|
||||||
{:keys [::transform] :or {transform identity} :as opts} scope]
|
|
||||||
(ensure-handler! path data scope)
|
(ensure-handler! path data scope)
|
||||||
(let [middleware (expand (transform (expand middleware data opts)) data opts)]
|
(let [middleware (expand-and-transform middleware data opts)]
|
||||||
(map->Endpoint
|
(map->Endpoint
|
||||||
{:handler (compile-handler middleware handler)
|
{:handler (compile-handler middleware handler)
|
||||||
:middleware middleware
|
:middleware middleware
|
||||||
|
|
@ -101,7 +111,13 @@
|
||||||
[\"/users\" {:middleware [wrap-delete]
|
[\"/users\" {:middleware [wrap-delete]
|
||||||
:handler get-user}]])
|
:handler get-user}]])
|
||||||
|
|
||||||
See router options from [[reitit.core/router]]."
|
Options:
|
||||||
|
|
||||||
|
| key | description |
|
||||||
|
| -------------------------------|-------------|
|
||||||
|
| `:reitit.middleware/transform` | Function of `[Middleware] => [Middleware]` to transform the expanded Middleware (default: identity).
|
||||||
|
|
||||||
|
See other router options from [[reitit.core/router]]."
|
||||||
([data]
|
([data]
|
||||||
(router data nil))
|
(router data nil))
|
||||||
([data opts]
|
([data opts]
|
||||||
|
|
@ -116,11 +132,3 @@
|
||||||
:result
|
:result
|
||||||
:handler))
|
:handler))
|
||||||
{::router router}))
|
{::router router}))
|
||||||
|
|
||||||
(defn chain
|
|
||||||
"Creates a vanilla ring middleware chain out of sequence of
|
|
||||||
IntoMiddleware thingies."
|
|
||||||
([middleware handler data]
|
|
||||||
(chain middleware handler data nil))
|
|
||||||
([middleware handler data opts]
|
|
||||||
(compile-handler (expand middleware data opts) handler)))
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
(ns reitit.ring.coercion-middleware
|
(ns reitit.ring.coercion-middleware
|
||||||
(:require [reitit.middleware :as middleware]
|
(:require [reitit.coercion :as coercion]
|
||||||
[reitit.coercion :as coercion]
|
|
||||||
[reitit.impl :as impl]))
|
[reitit.impl :as impl]))
|
||||||
|
|
||||||
(defn handle-coercion-exception [e respond raise]
|
(defn handle-coercion-exception [e respond raise]
|
||||||
|
|
@ -22,53 +21,50 @@
|
||||||
"Middleware for pluggable request coercion.
|
"Middleware for pluggable request coercion.
|
||||||
Expects a :coercion of type `reitit.coercion/Coercion`
|
Expects a :coercion of type `reitit.coercion/Coercion`
|
||||||
and :parameters from route data, otherwise does not mount."
|
and :parameters from route data, otherwise does not mount."
|
||||||
(middleware/create
|
{:name ::coerce-parameters
|
||||||
{:name ::coerce-parameters
|
:compile (fn [{:keys [coercion parameters]} opts]
|
||||||
:compile (fn [{:keys [coercion parameters]} opts]
|
(if (and coercion parameters)
|
||||||
(if (and coercion parameters)
|
(let [coercers (coercion/request-coercers coercion parameters opts)]
|
||||||
(let [coercers (coercion/request-coercers coercion parameters opts)]
|
(fn [handler]
|
||||||
(fn [handler]
|
(fn
|
||||||
(fn
|
([request]
|
||||||
([request]
|
(let [coerced (coercion/coerce-request coercers request)]
|
||||||
(let [coerced (coercion/coerce-request coercers request)]
|
(handler (impl/fast-assoc request :parameters coerced))))
|
||||||
(handler (impl/fast-assoc request :parameters coerced))))
|
([request respond raise]
|
||||||
([request respond raise]
|
(let [coerced (coercion/coerce-request coercers request)]
|
||||||
(let [coerced (coercion/coerce-request coercers request)]
|
(handler (impl/fast-assoc request :parameters coerced) respond raise))))))))})
|
||||||
(handler (impl/fast-assoc request :parameters coerced) respond raise))))))))}))
|
|
||||||
|
|
||||||
(def coerce-response-middleware
|
(def coerce-response-middleware
|
||||||
"Middleware for pluggable response coercion.
|
"Middleware for pluggable response coercion.
|
||||||
Expects a :coercion of type `reitit.coercion/Coercion`
|
Expects a :coercion of type `reitit.coercion/Coercion`
|
||||||
and :responses from route data, otherwise does not mount."
|
and :responses from route data, otherwise does not mount."
|
||||||
(middleware/create
|
{:name ::coerce-response
|
||||||
{:name ::coerce-response
|
:compile (fn [{:keys [coercion responses]} opts]
|
||||||
:compile (fn [{:keys [coercion responses]} opts]
|
(if (and coercion responses)
|
||||||
(if (and coercion responses)
|
(let [coercers (coercion/response-coercers coercion responses opts)]
|
||||||
(let [coercers (coercion/response-coercers coercion responses opts)]
|
(fn [handler]
|
||||||
(fn [handler]
|
(fn
|
||||||
(fn
|
([request]
|
||||||
([request]
|
(coercion/coerce-response coercers request (handler request)))
|
||||||
(coercion/coerce-response coercers request (handler request)))
|
([request respond raise]
|
||||||
([request respond raise]
|
(handler request #(respond (coercion/coerce-response coercers request %)) raise)))))))})
|
||||||
(handler request #(respond (coercion/coerce-response coercers request %)) raise)))))))}))
|
|
||||||
|
|
||||||
(def coerce-exceptions-middleware
|
(def coerce-exceptions-middleware
|
||||||
"Middleware for handling coercion exceptions.
|
"Middleware for handling coercion exceptions.
|
||||||
Expects a :coercion of type `reitit.coercion/Coercion`
|
Expects a :coercion of type `reitit.coercion/Coercion`
|
||||||
and :parameters or :responses from route data, otherwise does not mount."
|
and :parameters or :responses from route data, otherwise does not mount."
|
||||||
(middleware/create
|
{:name ::coerce-exceptions
|
||||||
{:name ::coerce-exceptions
|
:compile (fn [{:keys [coercion parameters responses]} _]
|
||||||
:compile (fn [{:keys [coercion parameters responses]} _]
|
(if (and coercion (or parameters responses))
|
||||||
(if (and coercion (or parameters responses))
|
(fn [handler]
|
||||||
(fn [handler]
|
(fn
|
||||||
(fn
|
([request]
|
||||||
([request]
|
(try
|
||||||
(try
|
(handler request)
|
||||||
(handler request)
|
(catch #?(:clj Exception :cljs js/Error) e
|
||||||
(catch #?(:clj Exception :cljs js/Error) e
|
(handle-coercion-exception e identity #(throw %)))))
|
||||||
(handle-coercion-exception e identity #(throw %)))))
|
([request respond raise]
|
||||||
([request respond raise]
|
(try
|
||||||
(try
|
(handler request respond #(handle-coercion-exception % respond raise))
|
||||||
(handler request respond #(handle-coercion-exception % respond raise))
|
(catch #?(:clj Exception :cljs js/Error) e
|
||||||
(catch #?(:clj Exception :cljs js/Error) e
|
(handle-coercion-exception e respond raise))))))))})
|
||||||
(handle-coercion-exception e respond raise))))))))}))
|
|
||||||
|
|
|
||||||
|
|
@ -1,75 +1,80 @@
|
||||||
(ns reitit.middleware-test
|
(ns reitit.middleware-test
|
||||||
(:require [clojure.test :refer [deftest testing is are]]
|
(:require [clojure.test :refer [deftest testing is are]]
|
||||||
[reitit.middleware :as middleware]
|
[reitit.middleware :as middleware]
|
||||||
[clojure.set :as set]
|
|
||||||
[reitit.core :as r])
|
[reitit.core :as r])
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(:import (clojure.lang ExceptionInfo))))
|
(:import (clojure.lang ExceptionInfo))))
|
||||||
|
|
||||||
|
(def request [])
|
||||||
|
|
||||||
|
(defn handler [request]
|
||||||
|
(conj request :ok))
|
||||||
|
|
||||||
|
(defn create [middleware]
|
||||||
|
(middleware/chain
|
||||||
|
middleware
|
||||||
|
handler
|
||||||
|
:data
|
||||||
|
nil))
|
||||||
|
|
||||||
(deftest expand-middleware-test
|
(deftest expand-middleware-test
|
||||||
|
|
||||||
(testing "middleware records"
|
(testing "middleware records"
|
||||||
|
|
||||||
(testing ":wrap & :compile are exclusive"
|
|
||||||
(is (thrown-with-msg?
|
|
||||||
ExceptionInfo
|
|
||||||
#"Middleware can't have both :wrap and :compile defined"
|
|
||||||
(middleware/create
|
|
||||||
{:name ::test
|
|
||||||
:wrap identity
|
|
||||||
:compile (constantly identity)}))))
|
|
||||||
|
|
||||||
(testing "middleware"
|
(testing "middleware"
|
||||||
(let [calls (atom 0)
|
(let [calls (atom 0)
|
||||||
wrap (fn [handler value]
|
wrap (fn [handler value]
|
||||||
(swap! calls inc)
|
(swap! calls inc)
|
||||||
(fn [request]
|
(fn [request]
|
||||||
[value request]))
|
(handler (conj request value))))]
|
||||||
->app (fn [ast handler]
|
|
||||||
(middleware/compile-handler
|
|
||||||
(middleware/expand ast :data {})
|
|
||||||
handler))]
|
|
||||||
|
|
||||||
(testing "as middleware function"
|
(testing "as function"
|
||||||
(reset! calls 0)
|
(reset! calls 0)
|
||||||
(let [app (->app [[#(wrap % :value)]] identity)]
|
(let [app (create [#(wrap % :value)])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= [:value :request] (app :request)))
|
(is (= [:value :ok] (app request)))
|
||||||
(is (= 1 @calls)))))
|
(is (= 1 @calls)))))
|
||||||
|
|
||||||
(testing "as middleware vector"
|
(testing "as function vector"
|
||||||
(reset! calls 0)
|
(reset! calls 0)
|
||||||
(let [app (->app [[wrap :value]] identity)]
|
(let [app (create [[#(wrap % :value)]])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= [:value :request] (app :request)))
|
(is (= [:value :ok] (app request)))
|
||||||
|
(is (= 1 @calls)))))
|
||||||
|
|
||||||
|
(testing "as function vector with value(s)"
|
||||||
|
(reset! calls 0)
|
||||||
|
(let [app (create [[wrap :value]])]
|
||||||
|
(dotimes [_ 10]
|
||||||
|
(is (= [:value :ok] (app request)))
|
||||||
(is (= 1 @calls)))))
|
(is (= 1 @calls)))))
|
||||||
|
|
||||||
(testing "as map"
|
(testing "as map"
|
||||||
(reset! calls 0)
|
(reset! calls 0)
|
||||||
(let [app (->app [[{:wrap #(wrap % :value)}]] identity)]
|
(let [app (create [[{:wrap #(wrap % :value)}]])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= [:value :request] (app :request)))
|
(is (= [:value :ok] (app request)))
|
||||||
(is (= 1 @calls)))))
|
(is (= 1 @calls)))))
|
||||||
|
|
||||||
(testing "as map vector"
|
(testing "as map vector"
|
||||||
(reset! calls 0)
|
(reset! calls 0)
|
||||||
(let [app (->app [[{:wrap wrap} :value]] identity)]
|
(let [app (create [[{:wrap wrap} :value]])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= [:value :request] (app :request)))
|
(is (= [:value :ok] (app request)))
|
||||||
(is (= 1 @calls)))))
|
(is (= 1 @calls)))))
|
||||||
|
|
||||||
(testing "as Middleware"
|
(testing "as Middleware"
|
||||||
(reset! calls 0)
|
(reset! calls 0)
|
||||||
(let [app (->app [[(middleware/create {:wrap #(wrap % :value)})]] identity)]
|
(let [app (create [[(middleware/map->Middleware {:wrap #(wrap % :value)})]])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= [:value :request] (app :request)))
|
(is (= [:value :ok] (app request)))
|
||||||
(is (= 1 @calls)))))
|
(is (= 1 @calls)))))
|
||||||
|
|
||||||
(testing "as Middleware vector"
|
(testing "as Middleware vector"
|
||||||
(reset! calls 0)
|
(reset! calls 0)
|
||||||
(let [app (->app [[(middleware/create {:wrap wrap}) :value]] identity)]
|
(let [app (create [[(middleware/map->Middleware {:wrap wrap}) :value]])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= [:value :request] (app :request)))
|
(is (= [:value :ok] (app request)))
|
||||||
(is (= 1 @calls)))))))
|
(is (= 1 @calls)))))))
|
||||||
|
|
||||||
(testing "compiled Middleware"
|
(testing "compiled Middleware"
|
||||||
|
|
@ -79,53 +84,52 @@
|
||||||
(fn [handler value]
|
(fn [handler value]
|
||||||
(swap! calls inc)
|
(swap! calls inc)
|
||||||
(fn [request]
|
(fn [request]
|
||||||
[data value request])))}
|
(handler (into request [data value])))))}
|
||||||
mw3 {:compile (fn [data _]
|
mw3 {:compile (fn [data _]
|
||||||
(swap! calls inc)
|
(swap! calls inc)
|
||||||
{:compile (fn [data _]
|
{:compile (fn [data _]
|
||||||
(swap! calls inc)
|
(swap! calls inc)
|
||||||
mw)})}
|
mw)})}]
|
||||||
->app (fn [ast handler]
|
|
||||||
(middleware/compile-handler
|
|
||||||
(middleware/expand ast :data {})
|
|
||||||
handler))]
|
|
||||||
|
|
||||||
(testing "as map"
|
(testing "as map"
|
||||||
(reset! calls 0)
|
(reset! calls 0)
|
||||||
(let [app (->app [[mw :value]] identity)]
|
(let [app (create [[mw :value]])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= [:data :value :request] (app :request)))
|
(is (= [:data :value :ok] (app request)))
|
||||||
(is (= 2 @calls)))))
|
(is (= 2 @calls)))))
|
||||||
|
|
||||||
(testing "as Middleware"
|
(testing "as Middleware"
|
||||||
(reset! calls 0)
|
(reset! calls 0)
|
||||||
(let [app (->app [[(middleware/create mw) :value]] identity)]
|
(let [app (create [[(middleware/map->Middleware mw) :value]])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= [:data :value :request] (app :request)))
|
(is (= [:data :value :ok] (app request)))
|
||||||
(is (= 2 @calls)))))
|
(is (= 2 @calls)))))
|
||||||
|
|
||||||
(testing "deeply compiled Middleware"
|
(testing "deeply compiled Middleware"
|
||||||
(reset! calls 0)
|
(reset! calls 0)
|
||||||
(let [app (->app [[(middleware/create mw3) :value]] identity)]
|
(let [app (create [[(middleware/map->Middleware mw3) :value]])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= [:data :value :request] (app :request)))
|
(is (= [:data :value :ok] (app request)))
|
||||||
(is (= 4 @calls)))))
|
(is (= 4 @calls)))))
|
||||||
|
|
||||||
(testing "too deeply compiled Middleware fails"
|
(testing "too deeply compiled Middleware fails"
|
||||||
(binding [middleware/*max-compile-depth* 2]
|
(binding [middleware/*max-compile-depth* 2]
|
||||||
(is (thrown? ExceptionInfo (->app [[(middleware/create mw3) :value]] identity)))))
|
(is (thrown?
|
||||||
|
ExceptionInfo
|
||||||
|
#"Too deep Middleware compilation"
|
||||||
|
(create [[(middleware/map->Middleware mw3) :value]])))))
|
||||||
|
|
||||||
(testing "nil unmounts the middleware"
|
(testing "nil unmounts the middleware"
|
||||||
(let [app (->app [{:compile (constantly nil)}
|
(let [app (create [{:compile (constantly nil)}
|
||||||
{:compile (constantly nil)}] identity)]
|
{:compile (constantly nil)}])]
|
||||||
(dotimes [_ 10]
|
(dotimes [_ 10]
|
||||||
(is (= :request (app :request))))))))))
|
(is (= [:ok] (app request))))))))))
|
||||||
|
|
||||||
(defn create-app [router]
|
(defn create-app [router]
|
||||||
(let [h (middleware/middleware-handler router)]
|
(let [h (middleware/middleware-handler router)]
|
||||||
(fn [path]
|
(fn [path]
|
||||||
(if-let [f (h path)]
|
(if-let [f (h path)]
|
||||||
(f [])))))
|
(f request)))))
|
||||||
|
|
||||||
(deftest middleware-handler-test
|
(deftest middleware-handler-test
|
||||||
|
|
||||||
|
|
@ -188,7 +192,7 @@
|
||||||
(map :name))))))))))
|
(map :name))))))))))
|
||||||
|
|
||||||
(deftest chain-test
|
(deftest chain-test
|
||||||
(testing "chain can produce middlware chain of any IntoMiddleware"
|
(testing "chain can produce middleware chain of any IntoMiddleware"
|
||||||
(let [mw (fn [handler value]
|
(let [mw (fn [handler value]
|
||||||
#(conj (handler (conj % value)) value))
|
#(conj (handler (conj % value)) value))
|
||||||
handler #(conj % :ok)
|
handler #(conj % :ok)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue