-
Notifications
You must be signed in to change notification settings - Fork 256
Middleware
Routes are Ring handler functions that return nil
if they do not match the incoming request. In many cases, this means that Ring middleware functions can be applied directly to routes.
For example, suppose we had some middleware that finds a user ID from the Ring session, and adds it to the request map for ease of access:
(defn wrap-current-user-id [handler]
(fn [request]
(let [user-id (-> request :session :user-id)]
(handler (assoc request :user-id user-id)))))
This middleware can be applied to individual routes without issue:
(wrap-current-user-id
(GET "/current-user" {:keys [user-id]}
(str "The current user ID is: " user-id)))
Or to several routes grouped by compojure.core/routes
or compojure.core/context
:
(wrap-current-user-id
(context "/user" {:keys [user-id]}
(GET "/current" ...)
(POST "/current" ...)))
Or to nested routes:
(routes
(GET "/" [] "Index")
(wrap-current-user-id
(GET "/current-user" {:keys [user-id]}
(str "The current user ID is: " user-id))))
If you want middleware to be applied only when a route matches, either because it has side effects or cannot deal with a nil
response, then you can use the compojure.core/wrap-routes
function.
For example, instead of taking the user ID from the session, perhaps we want to look up the user in a database. This is a more expensive operation, so ideally we only want this middleware to be applied if a route matches.
(defn wrap-current-user [handler database]
(fn [request]
(let [user-id (-> request :session :user-id)
user (get-user-by-id database user-id]
(handler (assoc request :user user)))))
To solve this problem, we can use wrap-routes
:
(wrap-routes wrap-current-user
(context "/user" {:keys [user]}
(GET "/current" ...)
(POST "/current" ...)))
The wrap-routes
function ensures that if the route matches, the middleware will be applied, and if it doesn't, then it won't be. This can be particularly useful when dealing with middleware that reads from the request body, or that has other side-effectful operations.