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
Full-time Web App Engineer, Digital Humanist, Researcher, Computer Psychologist