-
Notifications
You must be signed in to change notification settings - Fork 149
Creating your own metadata handlers
Tommi Reiman edited this page Feb 9, 2016
·
2 revisions
Compojure-api handles the route metadata by calling the multimethod compojure.api.meta/restructure-param
with
metadata key as a dispatch value.
Multimethods take three parameters:
- metadata key
- metadata value
- accumulator map with keys
-
:lets
, a vector of let bindings applied first before the actual body -
:letks
, a vector of letk bindings applied second before the actual body -
:middleware
, a vector of route specific middleware (applied from left to right) -
:swagger
, swaggerd-data of a route (without the key & value for the current multimethod) -
:body
, a sequence of the actual route body
-
.. and should return the modified accumulator. Multimethod calls are reduced to produce the final accumulator for
code generation. Defined key-value -based metadatas for routes are guaranteed to run on top-to-bottom order of the so
all the potential let
and letk
variable overrides can be solved by the client. Default implementation is to keep
the key & value as a route metadata.
Creating your own meta-data handler for role-based security.
(defn require-role! [required roles]
(if-not (seq (clojure.set/intersection required roles))
(ring.util.http-response/unauthorized! {:text "missing role", :required required, :roles roles})))
(defmethod compojure.api.meta/restructure-param :roles [_ roles acc]
(update-in acc [:lets] into ['_ `(require-role! ~roles (:roles ~'+compojure-api-request+))]))
Using it:
(GET "/admin" []
:roles #{:admin}
(ok {:message "welcome!"})))
(r {:request-method :get :uri "/admin"})
; => throws 401
(r {:request-method :get :uri "/admin" :roles #{:admin}})
; => ok
macroexpanding-1 it too see what's get generated:
; normal case
(macroexpand-1
`(GET "/admin" []
(ok {:message "welcome!"})))
; (compojure.api.routes/create
; "/admin"
; :get
; (compojure.api.meta/merge-parameters {})
; nil
; (compojure.core/make-route
; :get
; #clout.core.CompiledRoute{:source "/admin", :re #"/admin", :keys [], :absolute? false}
; (clojure.core/fn [request__14718__auto__]
; (compojure.core/let-request [[:as +compojure-api-request+] request__14718__auto__]
; (do (ring.util.http-response/ok {:message "welcome!"}))))))
(macroexpand-1
`(GET "/admin" []
:roles #{:admin}
(ok {:message "welcome!"})))
; (compojure.api.routes/create
; "/admin"
; :get
; (compojure.api.meta/merge-parameters {})
; nil
; (compojure.core/make-route
; :get
; #clout.core.CompiledRoute{:source "/admin", :re #"/admin", :keys [], :absolute? false}
; (clojure.core/fn [request__14718__auto__]
; (compojure.core/let-request [[:as +compojure-api-request+] request__14718__auto__]
; (clojure.core/let [_ (sampo.restructure/require-role! #{:admin} (:roles +compojure-api-request+))]
; (do (ring.util.http-response/ok {:message "welcome!"})))))))