Skip to content

Commit 45eef58

Browse files
committed
Handle middleware as data
Fixes metosin#202 Fixes metosin#190
1 parent 6938f2f commit 45eef58

File tree

4 files changed

+46
-22
lines changed

4 files changed

+46
-22
lines changed

CHANGELOG.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,14 @@
5252
Previously required a `type => matcher` map. Options are checked against `type => matcher` coercion input, and a
5353
descriptive error is thrown when api is created with the old options format.
5454

55-
* **TODO**: Middlewares
56-
57-
* **BREAKING** Renamed `middlewares` to `middleware` and `:middlewares` metahandler to `:middleware`
55+
* **BREAKING**: Renamed `middlewares` to `middleware` and `:middlewares` metahandler to `:middleware`
56+
57+
* **BREAKING**: Middleware must be defined as data: both our forms take a vector
58+
of middleware containing either a) fully configured mws (function)
59+
or b) a middleware templates in form [function args]. Nothing new, just best practices.
60+
* You can also use anonymous functions to create middleware with correct parameters:
61+
`(middleware [#(wrap-foo % {:opts :bar})])`
62+
* Similar to [duct](https://github.com/weavejester/duct/wiki/Components#handlers)
5863

5964
### Migration guide
6065

src/compojure/api/core.clj

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,24 @@
3333
(let [handlers (keep identity handlers)]
3434
(routes/create nil nil {} nil (ring-handler handlers))))
3535

36+
(defn middleware-fn [middleware]
37+
(if (vector? middleware)
38+
(let [[f & arguments] middleware]
39+
#(apply f % arguments))
40+
middleware))
41+
42+
(defn compose-middleware [middleware]
43+
(->> middleware
44+
(map middleware-fn)
45+
(apply comp identity)))
46+
3647
(defmacro middleware
3748
"Wraps routes with given middlewares using thread-first macro."
3849
[middleware & body]
39-
(let [middleware (reverse middleware)
40-
routes? (> (count body) 1)]
41-
`(let [body# ~(if routes? `(routes ~@body) (first body))]
42-
(routes/create "" nil {} [body#] (-> body# ~@middleware)))))
50+
(let [routes? (> (count body) 1)]
51+
`(let [body# ~(if routes? `(routes ~@body) (first body))
52+
wrap-mw# (compose-middleware ~middleware)]
53+
(routes/create "" nil {} [body#] (wrap-mw# body#)))))
4354

4455
(defmacro context [& args] (meta/restructure nil args {:routes 'routes}))
4556

src/compojure/api/meta.clj

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@
251251

252252
; Applies the given vector of middlewares to the route
253253
(defmethod restructure-param :middleware [_ middleware acc]
254-
(assert (and (vector? middleware) (every? (comp ifn? eval) middleware)))
254+
(assert (and (vector? middleware) (every? #(or (and (vector? %1) (ifn? (first %1))) (ifn? %1)) middleware)))
255255
(update-in acc [:middleware] into (reverse middleware)))
256256

257257
; Bind to stuff in request components using letk syntax
@@ -260,7 +260,7 @@
260260

261261
; route-specific override for coercers
262262
(defmethod restructure-param :coercion [_ coercion acc]
263-
(update-in acc [:middleware] conj `(mw/wrap-coercion ~coercion)))
263+
(update-in acc [:middleware] conj [mw/wrap-coercion coercion]))
264264

265265
;;
266266
;; Impl
@@ -293,11 +293,16 @@
293293
;; Api
294294
;;
295295

296-
(defmacro route-middleware
297-
"Wraps route body in mock-handler and middlewares."
298-
[middleware body arg]
299-
(let [middleware (reverse middleware)]
300-
`((-> (fn [~arg] ~body) ~@middleware) ~arg)))
296+
(defn middleware-fn [middleware]
297+
(if (vector? middleware)
298+
(let [[f & arguments] middleware]
299+
#(apply f % arguments))
300+
middleware))
301+
302+
(defn compose-middleware [middleware]
303+
(->> (reverse middleware)
304+
(map middleware-fn)
305+
(apply comp identity)))
301306

302307
(defn- destructure-compojure-api-request
303308
"Returns a vector of four elements:
@@ -322,7 +327,7 @@
322327

323328
(defn restructure [method [path arg & args] {:keys [routes]}]
324329
(let [[parameters body] (extract-parameters args)
325-
[lets letks responses middleware] [[] [] nil nil]
330+
[lets letks responses middleware] [[] [] nil []]
326331
[path-string lets arg-with-request arg] (destructure-compojure-api-request path lets arg)
327332

328333
{:keys [lets
@@ -342,7 +347,10 @@
342347
form `(~wrap ~@body)
343348
form (if (seq letks) `(letk ~letks ~form) form)
344349
form (if (seq lets) `(let ~lets ~form) form)
345-
form (if (seq middleware) `(route-middleware ~middleware ~form ~arg) form)
350+
form (if (seq middleware)
351+
`(let [wrap-mw# (compose-middleware ~middleware)]
352+
((wrap-mw# (fn [~arg] ~form)) ~arg))
353+
form)
346354
form (if routes
347355
`(compojure.core/context ~path ~arg-with-request ~form)
348356
(compojure.core/compile-route method path arg-with-request (list form)))

test/compojure/api/integration_test.clj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,13 @@
7979

8080
(facts "middleware"
8181
(let [app (api
82-
(middleware [middleware* (middleware* 2)]
82+
(middleware [middleware* [middleware* 2]]
8383
(context "/middlewares" []
8484
(GET "/simple" req (reply-mw* req))
85-
(middleware [(middleware* 3) (middleware* 4)]
85+
(middleware [[middleware* 3] [middleware* 4]]
8686
(GET "/nested" req (reply-mw* req))
8787
(GET "/nested-declared" req
88-
:middleware [(middleware* 5) (middleware* 6)]
88+
:middleware [[middleware* 5] [middleware* 6]]
8989
(reply-mw* req))))))]
9090

9191
(fact "are applied left-to-right"
@@ -108,7 +108,7 @@
108108
(GET "/first" []
109109
(ok {:value "first"}))
110110
(GET "/second" []
111-
:middleware [(constant-middleware (ok {:value "foo"}))]
111+
:middleware [[constant-middleware (ok {:value "foo"})]]
112112
(ok {:value "second"}))
113113
(GET "/third" []
114114
(ok {:value "third"})))]
@@ -520,7 +520,7 @@
520520
(swagger-docs)
521521
(GET "/middleware" []
522522
:query-params [x :- String]
523-
:middleware [(constant-middleware (ok 1))]
523+
:middleware [[constant-middleware (ok 1)]]
524524
(ok 2)))]
525525

526526
(fact "api-docs"
@@ -1050,7 +1050,7 @@
10501050

10511051
(fact "more swagger-data can be (deep-)merged in - either via swagger-docs at runtime via mws, fixes #170"
10521052
(let [app (api
1053-
(middleware [(rsm/wrap-swagger-data {:paths {"/runtime" {:get {}}}})]
1053+
(middleware [[rsm/wrap-swagger-data {:paths {"/runtime" {:get {}}}}]]
10541054
(swagger-docs
10551055
{:info {:version "2.0.0"}
10561056
:paths {"/extra" {:get {}}}})

0 commit comments

Comments
 (0)