ring-swagger

ring-swagger & compojure-api
salokristian 2019-02-27T13:25:33.026200Z

I have created a custom route metadata handler, auth-rules, for checking permissions. Sometimes these permission checks require access to data in e.g. the response body. Accessing the data is done before compojure-api validates and coerces the data, forcing me to validate it and thus re-implement stuff done anyways by compojure-api. This could be done by simply wrapping the route handler function in a permissions check, but I would like to maintain this declarative approach to permission checking. Would it be possible to have compojure-api run the response validation and coercion before executing this permission handler, and also access the coerced data in the handler? An example endpoint with custom permission handler:

(api/POST "/" {user-id :identity}
     :auth-rules instrument/instrument-owner?
     :summary "Create a new exercise session"
     :body [exercise-session-data ::spec/exercise-session-data]
     :return ::spec/exercise-session
     (let [exercise-session (assoc exercise-session-data :user-id user-id)
          id (db/create-exercise-session! exercise-session)]
       (res/created nil (merge exercise-session id))))
 
Permission handler (where I'd like to access validated exercise-session-data as defined in the body of the above endpoint):
(defn instrument-owner? [{user-id :identity
                           {:keys [instrument-id]} :body-params}]
   (let [instrument (db/find-instrument-by-id {:id instrument-id})]
     (= (:user-id instrument) user-id)))
 
auth-rules implementation:
(defn- wrap-restricted [handler rule]
  (rules/restrict handler {:handler rule
                           :on-error on-auth-error}))

(defmethod restructure-param :auth-rules
  [_ rule acc]
  (update-in acc [:middleware] conj [wrap-restricted rule]))

2019-02-27T14:50:49.026900Z

maybe you could implement it as a :middleware instead? https://github.com/metosin/compojure-api/wiki/Middleware

salokristian 2019-02-27T14:54:37.027800Z

The current solution is implemented as a route-specific middleware function. The problem is that I can't access the coerced params from a middleware function

2019-02-27T15:43:17.029600Z

in compojure-api.meta:

(defmethod restructure-param :coercion [_ coercion acc]
  (-> acc
      (assoc-in [:info :coercion] coercion)
      (update-in [:middleware] conj [`mw/wrap-coercion coercion])))
maybe you can put your own coercion before the :auth-rules and remove the old one?

ikitommi 2019-02-27T15:49:13.031700Z

That should work. Also, you can try to reorganize the middleware in the :auth-rules restructuring.

salokristian 2019-02-27T15:51:22.032500Z

Great, thanks for the quick help!