diff --git a/advanced/configuring_routers.html b/advanced/configuring_routers.html index 062c406d..1d688a01 100644 --- a/advanced/configuring_routers.html +++ b/advanced/configuring_routers.html @@ -525,7 +525,7 @@ diff --git a/advanced/different_routers.html b/advanced/different_routers.html index f27d6dbd..f03ef1c9 100644 --- a/advanced/different_routers.html +++ b/advanced/different_routers.html @@ -524,7 +524,7 @@ diff --git a/advanced/index.html b/advanced/index.html index 77eb8f6e..77228d35 100644 --- a/advanced/index.html +++ b/advanced/index.html @@ -487,7 +487,7 @@ diff --git a/advanced/route_validation.html b/advanced/route_validation.html index 4d1c720e..51b5868c 100644 --- a/advanced/route_validation.html +++ b/advanced/route_validation.html @@ -636,7 +636,7 @@ diff --git a/basics/index.html b/basics/index.html index be36e4ee..ec482fa4 100644 --- a/basics/index.html +++ b/basics/index.html @@ -490,7 +490,7 @@ diff --git a/basics/name_based_routing.html b/basics/name_based_routing.html index 42c2fe20..5304eb8a 100644 --- a/basics/name_based_routing.html +++ b/basics/name_based_routing.html @@ -531,7 +531,7 @@ diff --git a/basics/path_based_routing.html b/basics/path_based_routing.html index 6f373213..34c53e1e 100644 --- a/basics/path_based_routing.html +++ b/basics/path_based_routing.html @@ -509,7 +509,7 @@ diff --git a/basics/route_conflicts.html b/basics/route_conflicts.html index bf6ab4ed..5fe62c6b 100644 --- a/basics/route_conflicts.html +++ b/basics/route_conflicts.html @@ -526,7 +526,7 @@ diff --git a/basics/route_data.html b/basics/route_data.html index d3e4518a..2055f9cc 100644 --- a/basics/route_data.html +++ b/basics/route_data.html @@ -560,7 +560,7 @@ diff --git a/basics/route_syntax.html b/basics/route_syntax.html index d3c47129..24b5e4d8 100644 --- a/basics/route_syntax.html +++ b/basics/route_syntax.html @@ -539,7 +539,7 @@ diff --git a/basics/router.html b/basics/router.html index e5632994..46bfb2cd 100644 --- a/basics/router.html +++ b/basics/router.html @@ -519,7 +519,7 @@ diff --git a/faq.html b/faq.html index f8852725..f90831c5 100644 --- a/faq.html +++ b/faq.html @@ -476,7 +476,7 @@ diff --git a/index.html b/index.html index b1397a61..b0aeaf80 100644 --- a/index.html +++ b/index.html @@ -593,7 +593,7 @@ diff --git a/performance.html b/performance.html index 654a7ace..6debeacb 100644 --- a/performance.html +++ b/performance.html @@ -562,7 +562,7 @@ diff --git a/ring/coercion.html b/ring/coercion.html index 1abe87bd..994644c4 100644 --- a/ring/coercion.html +++ b/ring/coercion.html @@ -657,7 +657,7 @@ diff --git a/ring/compiling_middleware.html b/ring/compiling_middleware.html index c610d27e..010dd427 100644 --- a/ring/compiling_middleware.html +++ b/ring/compiling_middleware.html @@ -543,7 +543,7 @@ diff --git a/ring/data_driven_middleware.html b/ring/data_driven_middleware.html index 92e66977..71121621 100644 --- a/ring/data_driven_middleware.html +++ b/ring/data_driven_middleware.html @@ -439,13 +439,15 @@

Data-driven Middleware

-

Ring defines middleware as a function of type handler & args => request => response. It's easy to undrstand and enables great performance. Still, in the end - the middleware-chain is just a opaque function, making things like documentation and debugging hard.

-

Reitit does things bit differently:

+

Ring defines middleware as a function of type handler & args => request => response. It's relatively easy to understand and enables good performance. Downside is that the middleware-chain is just a opaque function, making things like debugging and composition hard. It's too easy to apply the middleware in wrong order.

+

Reitit defines middleware as data:

    -
  1. Middleware is defined as a vector (of middleware) enabling the chain to be malipulated before turned into the runtime middleware function.
  2. Middleware can be defined as first-class data entries
  3. +
  4. Middleware can be defined as a duct-style vector (of middleware)
  5. +
  6. Middleware can be optimized & compiled againt an endpoint
  7. +
  8. Middleware chain can be transformed by the router
-

Middleware as data

+

Middleware as data

All values in the :middleware vector in the route data are coerced into reitit.ring.middleware/Middleware Records with using the reitit.ring.middleware/IntoMiddleware Protocol. By default, functions, maps and Middleware records are allowed.

Records can have arbitrary keys, but the following keys have a special purpose:

@@ -474,7 +476,7 @@

For the actual request processing, the Records are unwrapped into normal functions and composed into a middleware function chain, yielding zero runtime penalty.

Creating Middleware

The following produce identical middleware runtime function.

-

Function

+

Function

(defn wrap [handler id]
   (fn [request]
     (handler (update request ::acc (fnil conj []) id))))
@@ -488,13 +490,14 @@
      :description "Middleware that does things."
      :wrap wrap}))
 
-

Map

+

Map

(def wrap3
   {:name ::wrap3
    :description "Middleware that does things."
    :wrap wrap})
 
-

Using Middleware

+

Using Middleware

+

:middleware is merged to endpoints by the router.

(require '[reitit.ring :as ring])
 
 (defn handler [{:keys [::acc]}]
@@ -507,14 +510,43 @@
        ["/ping" {:get {:middleware [[wrap3 3]]
                        :handler handler}}]])))
 
-

All the middleware are called correctly:

+

All the middleware are applied correctly:

(app {:request-method :get, :uri "/api/ping"})
 ; {:status 200, :body [1 2 3 :handler]}
 
-

Future

+

Compiling middleware

+

Middleware can be optimized against an endpoint using middleware compilation.

+

Transforming the middleware chain

+

There is an extra option in ring-router (actually, in the undelaying middleware-router): :reitit.ring.middleware/transform to transform the middleware chain per endpoint. It sees the vector of compiled middleware and should return a new vector of middleware.

+

Adding debug middleware between all other middleware

+
(def app
+  (ring/ring-handler
+    (ring/router
+      ["/api" {:middleware [[wrap 1] [wrap2 2]]}
+       ["/ping" {:get {:middleware [[wrap3 3]]
+                       :handler handler}}]]
+      {::middleware/transform #(interleave % (repeat [wrap :debug]))})))
+
+
(app {:request-method :get, :uri "/api/ping"})
+; {:status 200, :body [1 :debug 2 :debug 3 :debug :handler]}
+

Reversing the middleware chain

+
(def app
+  (ring/ring-handler
+    (ring/router
+      ["/api" {:middleware [[wrap 1] [wrap2 2]]}
+       ["/ping" {:get {:middleware [[wrap3 3]]
+                       :handler handler}}]]
+      {::middleware/transform reverse)})))
+
+
(app {:request-method :get, :uri "/api/ping"})
+; {:status 200, :body [3 2 1 :handler]}
+

Roadmap for middleware

Some things bubblin' under: