0
votes

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.

1
I've tried to assoc it with the request ... I've had success doing exactly that. Can you show how you tried to do that and how you tried to access it later? - jas

1 Answers

3
votes

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.