Fine-grained per-method middleware use with Reitit

Table of Contents

img

Fact: I have middleware performing authentication (in this case, my CAS authentication middleware) Need: This middleware should apply to client-facing SPA-rendered views, which are requested via GET.

  • Constraint: This middleware does NOT apply to non-get routes (which are headless so the authentication must be handled differently)
  • Constraint: There exist headless GET routes, too, which should not be CAS authenticated
  • Constraint: Individual routes may have a CAS-authenticated GET response, as well as non-CAS POST, PATCH, and DELETE responses

Reitit allowed me to specify middleware on a delightfully granular level to solve this. Here’s how it looks:

(defn front-cas-get [& merge-maps]
  "Serve the homepage to GET requests, with CAS authentication"
  (let [base {:get {:handler home-page
                    :middleware [middleware/wrap-cas]}}]
    (apply merge base merge-maps)))

(defn home-routes
  []
  ["" {:middleware [middleware/wrap-base
                    middleware/wrap-formats]}
   ["/" (front-cas-get)] ;; includes the dashboard
   ["/form"
    ["/:form-id" (front-cas-get
                  {:post submit-initial-form
                   #_(:patch nil
                      :delete nil)})]]])

You can see the result on the POST "/:form-id" route, which has no CAS middleware, while the GET "/:form-id" is under CAS. Of course, future iterations will apply other authorization middleware to those other routes. Exactly as desired!

Tory Anderson avatar
Tory Anderson
Web App Engineer, Digital Humanist, Researcher, Computer Psychologist