Skip to content

Middleware

James Reeves edited this page Jan 4, 2020 · 4 revisions

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:

(-> (context "/user" {:keys [user]}
      (GET  "/current" ...)
      (POST "/current" ...))
    (wrap-routes wrap-current-user))

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.

You can’t perform that action at this time.