Hi all
How do I add an extra interceptor to Pedestal Lacinia?
This does not work:
(def my-interceptor
{:name ::my-interceptor
:enter (fn [context]
(log/info "hello!" context)
context)})
(defn interceptors [compiled-schema]
(let [options {}]
(conj (pedestal/default-interceptors compiled-schema options)
my-interceptor)))
(defrecord Server [schema-provider server port]
component/Lifecycle
(start [this]
(let [compiled-schema (:schema schema-provider)]
(assoc this :server (-> compiled-schema
(pedestal/service-map {:graphiql true
:port port
:interceptors (interceptors compiled-schema)})
http/create-server
http/start))))
(stop [this]
(http/stop server)
(assoc this :server nil)))
Thanks!
What does use of inject
look like?
Ah I see a test like this:
deftest inject-before
(let [fred {:name :fred}
barney {:name :barney}
wilma {:name :wilma}]
(is (= [fred wilma barney]
(inject [fred barney] wilma :before :barney)))))
And I should put it before :name :io.pedestal.http.impl.servlet-interceptor/ring-response
Adding after inject-app-context does not provide data on the context…
(defn- inject-roles-interceptor [interceptors]
(pedestal/inject interceptors
roles-interceptor
:after
::pedestal/inject-app-context))
But the context is empty in the resolver
(defn- use-roles-resolver
[ds {:keys [columns]}]
(fn [{:auth/keys [roles] :as context} data _]
(log/info roles)
(log/info context)
))
(defn- resolver-map
[ds]
{:query/component-basic (use-roles-resolver ds)})
Does not print the roles that are added by the interceptor…It does not have an added key
Any idea why? Should I inject somehwere else?
I didn't notice example interceptor from you, did I miss it or did you not post it? Did you add the required key into :lacinia-app-context
inside of the context?
Example of interceptor (untested) that adds key :custom-role-key
inside context with value :some-value
(def roles-interceptor
{:enter (fn [context]
(assoc-in context [:lacinia-app-context :custom-role-key] :some-value})
Aaaaaaaaaaaha
I added it to the context
Not the lacinia-app-context
Awesome thanks a lot
Hmm that also does not work
I now try replacing the full inject-app-context
interceptor with my own code
This also does not work:
(defn my-own-inject-app-context-interceptor
"Adds a `:lacinia-app-context` key to the request, used when executing the query.
The provided app-context map is augmented with the request map, as
key `:request`.
The interceptor extracts authentication information from the request and
exposes that as the app-context's `:auth/roles` key."
{:added "0.2.0"}
[app-context]
(interceptor
{:name ::inject-app-context
:enter (fn [context]
(let [roles (get-roles context)]
(assoc-in context [:request :lacinia-app-context]
(assoc app-context :request (:request context) :auth/roles roles)))}))
(defn- inject-roles-interceptor [interceptors]
"Replace the default interceptor that creates the app context with one that also
validates and retrieves the roles from the JWT and adds those to the
app-context under the `:auth/roles` key."
(pedestal/inject interceptors
my-own-inject-app-context-interceptor
:replace
::pedestal/inject-app-context))
Nothing available
Not even the request then
Ah maybe this one should begin with :request
(def roles-interceptor
{:enter (fn [context]
(assoc-in context [:lacinia-app-context :custom-role-key] :some-value})
So :request :lacinina-app-context
Goal is to access the JWT token in the x-auth-token header of the HTTP request
Ah I heard from a colleague that the request is also available in the context of a resolver
It should work as default-interceptors
function returns vector of interceptors: https://github.com/walmartlabs/lacinia-pedestal/blob/2e7a7b82742c09a9f65ff30ecccb7c4e8f906799/src/com/walmartlabs/lacinia/pedestal.clj#L416
The thing is though that the last of the default interceptors probably adds response to the context: https://github.com/walmartlabs/lacinia-pedestal/blob/2e7a7b82742c09a9f65ff30ecccb7c4e8f906799/src/com/walmartlabs/lacinia/pedestal.clj#L354 which causes pedestal to omit rest of the interceptors: http://pedestal.io/reference/servlet-interceptor#_early_termination so your interceptor even if present is not called.
If you want to add your own interceptor, you should add it before last default interceptor. You can use inject
helper fn for that: https://github.com/walmartlabs/lacinia-pedestal/blob/2e7a7b82742c09a9f65ff30ecccb7c4e8f906799/src/com/walmartlabs/lacinia/pedestal.clj#L81
and yes. :request
is available to field resolvers, thanks to this interceptor: https://github.com/walmartlabs/lacinia-pedestal/blob/2e7a7b82742c09a9f65ff30ecccb7c4e8f906799/src/com/walmartlabs/lacinia/pedestal.clj#L318
(you can create your own interceptor that will add more stuff into context and inject it after inject-app-context-interceptor
)
Yep, under :request