Skip to content

Commit 50631b5

Browse files
committed
Add 'Middleware' section
1 parent b18262f commit 50631b5

File tree

1 file changed

+107
-1
lines changed

1 file changed

+107
-1
lines changed

index.adoc

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ route to handle a web request to the root of our application.
637637
:routes [["/" {:get :todo.routes/index}]]}}}
638638
----
639639

640-
Then we'll create a handler function for that route.
640+
Then we'll create a Ring **handler** function for that route.
641641

642642
.src/todo/routes.clj
643643
[,clojure]
@@ -779,6 +779,112 @@ Or we could return the string directly:
779779
All of these examples are equivalent, but returning a vector is the most
780780
convenient and concise.
781781

782+
783+
=== Middleware
784+
785+
Ring **middleware** are functions that transform Ring handlers. These
786+
are often used to parse information from the request map, such as
787+
encoded parameters or session data, or to transform the response map, by
788+
adding headers or formatting the response body.
789+
790+
In the previous section we saw how a Hiccup data structure could be
791+
directly attached to the response body. This is possible because Duct
792+
adds default middleware to look for Hiccup and format it into HTML.
793+
794+
Let's create some middleware that will add a map of custom headers to
795+
every response:
796+
797+
.src/todo/middleware.clj
798+
[,clojure]
799+
----
800+
(ns todo.middleware)
801+
802+
(defn wrap-headers [headers]
803+
(fn [handler]
804+
(fn [request)
805+
(let [response (handler request)]
806+
(update response :headers merge headers)))))
807+
----
808+
809+
Once we've created the middleware function, we can give it to the web
810+
module via the `:middleware` key:
811+
812+
.duct.edn
813+
[,clojure]
814+
----
815+
{:system
816+
{:duct.module/logging {}
817+
:duct.module/web
818+
{:features #{:site}
819+
:middleware [#ig/ref :todo.middleware/wrap-headers]
820+
:routes [["/" {:get :todo.routes/index}]]}
821+
822+
:todo.middleware/wrap-headers {"X-Powered-By" "Duct"}}}
823+
----
824+
825+
We add a new key, `:todo.middleware/wrap-headers`, which configures and
826+
creates the middleware function, then we use an Integrant ref to add
827+
that function to a vector of middleware.
828+
829+
There three ways to apply middleware:
830+
831+
* Middleware is applied to all requests (via `:middleware`)
832+
* Middleware is applied if any route matches (via `:route-middleware`)
833+
* Middleware is applied if a **specific** route matches (via
834+
`:middleware` attached to individual routes)
835+
836+
The previous example demonstrated how to apply middleware to all
837+
requests. However, sometimes you only want middleware to apply if at
838+
least one route matches. For example:
839+
840+
.duct.edn
841+
[,clojure]
842+
----
843+
{:system
844+
{:duct.module/logging {}
845+
:duct.module/web
846+
{:features #{:site}
847+
:route-middleware [#ig/ref :todo.middleware/wrap-headers]
848+
:routes [["/" {:get :todo.routes/index}]]}
849+
850+
:todo.middleware/wrap-headers {"X-Route-Matches" "True"}}}
851+
----
852+
853+
This will add the extra header only if the route matches. It won't be
854+
added to the default 404 response that is returned when all routes fail
855+
to match.
856+
857+
Finally, you can attach middleware to specific routes, or groups of
858+
nested routes by adding the `:middleware` key to the route itself:
859+
860+
.duct.edn
861+
[,clojure]
862+
----
863+
{:system
864+
{:duct.module/logging {}
865+
:duct.module/web
866+
{:features #{:site}
867+
:routes [["/" {:get :todo.routes/index
868+
:middleware [#ig/ref :todo.middleware/wrap-headers]}]]}
869+
870+
:todo.middleware/wrap-headers {"X-Index-Route" "True"}}}
871+
----
872+
873+
The web module adds a lot of its own middleware, depending on the
874+
`:features` you choose. Often this is enough, and so we'll remove the
875+
custom middleware for now; it won't be needed for the rest of this
876+
document.
877+
878+
.duct.edn
879+
[,clojure]
880+
----
881+
{:system
882+
{:duct.module/logging {}
883+
:duct.module/web
884+
{:features #{:site}
885+
:routes [["/" {:get :todo.routes/index}]]}}}
886+
----
887+
782888
=== SQL Database
783889

784890
The next step is to add a database to our application. We'll use

0 commit comments

Comments
 (0)