Fork me on GitHub

How to deal with auth on lacinia? There is some way to process app-context before it come to "handler/resolver"?


I think you need to add some custom interceptor then,


So, I will not use lacinia-pedestal (just parts of it)


The ideas in lacinia-pedestal can be adapted to other frameworks, such as Ring. Internally, we use pedestal so that's what we're prepared to develop and maintain.


What we do is we have a standard ring middleware stack including JWT auth, and the handler that calls (lacinia/execute) is wrapped underneath that


The other thing we do is that when a user is authenticated, we add a key to the app-context that corresponds to the logged-in user, then in the resolvers we access that if we need to restrict access to some fields based on what user is requesting it


It's all based on adding stuff to the request object in middleware in standard Ring fashion. I imagine you'd use interceptors for the same thing in pedestal, we aren't using lacinia-pedestal ourselves


Our code looks roughly like:

(defn create-context [request]
  (let [db   (dlib/get-db)
        user (dlib/db-entity db (:identity request) :person/slug)]
    {:ocp.lacinia/db         db
     :ocp.lacinia/user       user
     :ocp.lacinia/request-id (d/squuid)}))

(defn query-handler
  (let [query     (get-in request [:params :query])
        variables (get-in request [:params :variables])
        context   (create-context request)
        result    (lacinia/execute (ocl/load-schema) query variables context)]


The interceptor complexity in lacinia-pedestal is driven by the desire to get default behavior, and allow for the "slotting" of additional logic, such as auth, between the established steps. Internally, we also do odd things such as rewriting the query to support older clients that submit invalid GraphQL (that pre-release versions of Lacinia accepted as valid). That's why, for example, we extract the query, variables, and operation name in one step, parse it in a second step, and execute it in a third.


But if you are writing for Ring, from scratch, you can easily push these multiple steps together into a single handler.


Whatever works for you.