mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 00:11:11 +00:00
It's possible to put the :keys keyword in the namespace of the keys one likes to destructure. With that one can use symbols in the vector again. One advantage of having symbols is, that Cursive grays them out if not used. I found two occurrences of unused destructured keys.
1.5 KiB
1.5 KiB
Dynamic Extensions
ring-handler injects the Match into a request and it can be extracted at runtime with reitit.ring/get-match. This can be used to build ad-hoc extensions to the system.
Example middleware to guard routes based on user roles:
(require '[reitit.ring :as ring])
(require '[clojure.set :as set])
(defn wrap-enforce-roles [handler]
(fn [{::keys [roles] :as request}]
(let [required (some-> request (ring/get-match) :data ::roles)]
(if (and (seq required) (not (set/subset? required roles)))
{:status 403, :body "forbidden"}
(handler request)))))
Mounted to an app via router data (affecting all routes):
(def handler (constantly {:status 200, :body "ok"}))
(def app
(ring/ring-handler
(ring/router
[["/api"
["/ping" handler]
["/admin" {::roles #{:admin}}
["/ping" handler]]]]
{:data {:middleware [wrap-enforce-roles]}})))
Anonymous access to public route:
(app {:request-method :get, :uri "/api/ping"})
; {:status 200, :body "ok"}
Anonymous access to guarded route:
(app {:request-method :get, :uri "/api/admin/ping"})
; {:status 403, :body "forbidden"}
Authorized access to guarded route:
(app {:request-method :get, :uri "/api/admin/ping", ::roles #{:admin}})
; {:status 200, :body "ok"}
Dynamic extensions are nice, but we can do much better. See data-driven middleware and compiling routes.