Skip to content
Jacob Emcken edited this page Jan 4, 2020 · 4 revisions

Adding middleware to routes (routes basically being a Ring handler function):

(def routes-without-middleware
  (context "/user/:user-id" [user-id]
    (GET "/profile" [] ...)
    (GET "/posts" [] ...)))

Regardless of it being in a context or not:

(defroutes routes-without-middleware
  (GET "/user/:user-id/profile" [user-id] ...)
  (GET "/user/:user-id/posts" [user-id] ...))

Is basically just wrapping it:

(def routes-with-middleware
  (wrap-some-middleware routes-without-middleware option1 option2))

Nested middleware wrapping

There is a catch, but middleware can be wrapped midway through the route definitions:

(defroutes my-routes
  (GET "/foo" [] ...)
  (-> (GET "/bar" [] ...)
      (wrap-some-middleware {:some-option 123}))
  (GET "/baz" [] ...)
  (route/not-found "<h1>Not found</h1>"))

Regardless of it wrapping a context or not:

(defroutes my-routes
  (GET "/foo" [] ...)  
  (-> (context "/my-context"
        (GET "/bar1" [] ...)        
        (GET "/bar2" [] ...))
      (wrap-some-middleware {:some-option 123}))
  (GET "/baz [] ...)
  (route/not-found "<h1>Not found</h1>"))

The catch is that wrap-some-middleware isn't applied until a request is being tried matched against the routes it's wrapping.

This means GET /foo always goes free, while every subsequent route (including GET /baz and the not-found fallback) always gets the middleware applied.

Apply middleware after match

What you are most likely looking for is wrap-routes.

(defroutes my-routes
  (GET "/foo" [] ...)
  (-> (GET "/bar" [] ...)
      (wrap-routes wrap-some-middleware {:some-option 123}))
  (GET "/baz" [] ...))

Which applies the middleware only if the route matches (i.e. GET /bar). Routes after (like GET /baz) isn't affected by the middleware.

The same applies when using context:

(defroutes my-routes
  (GET "/foo" [] ...)  
  (-> (context "/my-context"
        (GET "/bar1" [] ...)        
        (GET "/bar2" [] ...))
      (wrap- wrap-some-middleware {:some-option 123}))
  (GET "/baz [] ...))

Again the GET /baz route isn't affected by the middleware applied to the context /my-context.

Multiple middleware

Oftentimes multiple middleware are wanted and using routes-without-middleware from the top it would look like:

(def routes-with-multiple-middleware
  (->
    routes-without-middleware
    (wrap-some-middleware option1 option2)
    (wrap-some-other-middleware)))

Dealing with middleware that is only desired on specific routes or contexts:

(defroutes my-routes
  (GET "/foo" [] ...)  
  (-> (context "/my-context"
        (GET "/bar1" [] ...)        
        (GET "/bar2" [] ...))
      (wrap-routes wrap-some-middleware {:some-option 123})
      (wrap-routes wrap-some-other-middleware))
  (GET "/baz [] ...))
Clone this wiki locally