Merge pull request #146 from metosin/top-level-mw

Support for top-level middleware
This commit is contained in:
Tommi Reiman 2018-09-22 21:50:55 +03:00 committed by GitHub
commit 86eac2ff92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 97 additions and 31 deletions

View file

@ -2,6 +2,35 @@
## `reitit-ring`
* `ring-handler` takes optionally a 3rd argument, an options map which can be used to se top-level middleware, applied before any routing is done:
```clj
(require '[reitit.ring :as ring])
(defn wrap [handler id]
(fn [request]
(handler (update request ::acc (fnil conj []) id))))
(defn handler [{:keys [::acc]}]
{:status 200, :body (conj acc :handler)})
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[mw :api]]}
["/get" {:get handler}]])
(ring/create-default-handler)
{:middleware [[mw :top]]}))
(app {:request-method :get, :uri "/api/get"})
; {:status 200, :body [:top :api :ok]}
(require '[reitit.core :as r])
(-> app (ring/get-router))
; #object[reitit.core$single_static_path_router]
```
* updated deps:
```clj

View file

@ -127,6 +127,21 @@ Middleware is applied correctly:
; {:status 200, :body [:api :admin :db :delete :handler]}
```
Top-level middleware, applied before any routing is done:
```clj
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[mw :api]]}
["/get" {:get handler}]])
nil
{:middleware [[mw :top]]}))
(app {:request-method :get, :uri "/api/get"})
; {:status 200, :body [:top :api :ok]}
```
# Async Ring
All built-in middleware provide both 2 and 3-arity and are compiled for both Clojure & ClojureScript, so they work with [Async Ring](https://www.booleanknot.com/blog/2016/07/15/asynchronous-ring.html) and [Node.js](https://nodejs.org) too.

View file

@ -177,41 +177,47 @@
(create handler)))))
(defn ring-handler
"Creates a ring-handler out of a ring-router.
Supports both 1 (sync) and 3 (async) arities.
Optionally takes a ring-handler which is called
in no route matches."
"Creates a ring-handler out of a router, optional default ring-handler
and options map, with the following keys:
| key | description |
| --------------|-------------|
| `:middleware` | Optional sequence of middleware that are wrap the [[ring-handler]]"
([router]
(ring-handler router nil))
([router default-handler]
(let [default-handler (or default-handler (fn ([_]) ([_ respond _] (respond nil))))]
(ring-handler router default-handler nil))
([router default-handler {:keys [middleware]}]
(let [default-handler (or default-handler (fn ([_]) ([_ respond _] (respond nil))))
wrap (if middleware (partial middleware/chain middleware) identity)]
(with-meta
(fn
([request]
(if-let [match (r/match-by-path router (:uri request))]
(let [method (:request-method request)
path-params (:path-params match)
result (:result match)
handler (-> result method :handler (or default-handler))
request (-> request
(impl/fast-assoc :path-params path-params)
(impl/fast-assoc ::r/match match)
(impl/fast-assoc ::r/router router))]
(or (handler request) (default-handler request)))
(default-handler request)))
([request respond raise]
(if-let [match (r/match-by-path router (:uri request))]
(let [method (:request-method request)
path-params (:path-params match)
result (:result match)
handler (-> result method :handler (or default-handler))
request (-> request
(impl/fast-assoc :path-params path-params)
(impl/fast-assoc ::r/match match)
(impl/fast-assoc ::r/router router))]
((routes handler default-handler) request respond raise))
(default-handler request respond raise))
nil))
(wrap
(fn
([request]
(if-let [match (r/match-by-path router (:uri request))]
(let [method (:request-method request)
path-params (:path-params match)
result (:result match)
handler (-> result method :handler (or default-handler))
request (-> request
(impl/fast-assoc :path-params path-params)
(impl/fast-assoc ::r/match match)
(impl/fast-assoc ::r/router router))]
(or (handler request) (default-handler request)))
(default-handler request)))
([request respond raise]
(if-let [match (r/match-by-path router (:uri request))]
(let [method (:request-method request)
path-params (:path-params match)
result (:result match)
handler (-> result method :handler (or default-handler))
request (-> request
(impl/fast-assoc :path-params path-params)
(impl/fast-assoc ::r/match match)
(impl/fast-assoc ::r/router router))]
((routes handler default-handler) request respond raise))
(default-handler request respond raise))
nil)))
{::r/router router}))))
(defn get-router [handler]

View file

@ -78,6 +78,22 @@
(is (= {:status 200, :body [:api :users :post :ok]}
@result))))))
(testing "with top-level middleware"
(let [router (ring/router
["/api" {:middleware [[mw :api]]}
["/get" {:get handler}]])
app (ring/ring-handler router nil {:middleware [[mw :top]]})]
(testing "router can be extracted"
(is (= router (ring/get-router app))))
(testing "not found"
(is (= nil (app {:uri "/favicon.ico"}))))
(testing "on match"
(is (= {:status 200, :body [:top :api :ok]}
(app {:uri "/api/get" :request-method :get}))))))
(testing "named routes"
(let [router (ring/router
[["/api"