newBieDev
newBieDev

Reputation: 504

Compojure Ring Middleware How To Use Value Outside of Middleware

I have a simple route and middleware setup with compojure/swagger that is utilizing a ring middleware.

(POST "/worlds" [request]
      :body-params [name :- String]
      :header-params [token :- String]
      :middleware [wrap-api-auth]
      :summary "Creates a new world with 'name'"
      (ok (do-something-with-user)

(defn wrap-api-auth [handler]
  (fn [request]
    (let
      [token (get (:headers request) "token")
       user (db/get-user-by-token token)]
      (if user
        (handler request)     ; pass to wrapped handler
        (unauthorized {:error "unauthorized"})))))

This defines a simple route with some basic auth. The token passed in the header param is used to make a database query, which either returns a user and continues, or returns false and fails.

What I'm trying to accomplish is to pass the returned user back out so that I can use it later. I haven't had any luck, as I don't really know where I would try to add it to that I could access it later. I've tried to assoc it with the request but it doesn't appear that I can access it later. The ideal situation is I'm able to pass it to the do-something-with-user function.

Upvotes: 0

Views: 308

Answers (1)

Stefan Kamphausen
Stefan Kamphausen

Reputation: 1665

Using assoc to add some data to the request should totally work.

You can find an example with some code that is very close to what I have in production at https://gist.github.com/ska2342/4567b02531ff611db6a1208ebd4316e6#file-gh-validation-clj-L124

In essence, that middleware calls

(handler (assoc request
                :validation {:valid true
                             :validation valid?}))

So for your case, the following should just work:

(handler (assoc request
                :user user))

If I understood correctly, the destructuring syntax you use is from compojure-api. According to the example at https://github.com/metosin/compojure-api/wiki/Middleware I'd say that the middleware set via the :middleware key behaves just as expected and you should be able to extract the :user from the request that ultimately ends up in your route.

So, just pass the request on to the do-something-with-user function:

(POST "/worlds" request
      :body-params [name :- String]
      :header-params [token :- String]
      :middleware [wrap-api-auth]
      :summary "Creates a new world with 'name'"
      (ok (do-something-with-user request))

It should contain the :user you assoced into it in your middleware function. Note the missing brackets around request like mentioned in the comments to this answer.

Upvotes: 3

Related Questions