I’m trying to bypass a middleware ensuring authentication, but I can’t make it work, I suspect because some magic happens with middleware, maybe. It’s the weirdest thing:
The first pain point is that there’s no easy way to get the meta.
I tried the method suggested in the docs:
type = Absinthe.Schema.lookup_type(MyAppWeb.GraphQL.Schema, :register_user)
Absinthe.Type.meta(type, :private)
But then it complains that the schema is not yet available:
= Compilation error in file lib/my_app_web/graphql/schema.ex ==
** (UndefinedFunctionError) function MyAppWeb.GraphQL.Schema.Compiled.absinthe_type/1 is undefined (module MyAppWeb.GraphQL.Schema.Compiled is not available)
The middleware are defined in the Schema (middleware/3
callback), just as in the book. I guess the function call does some introspection and the Schema has not finished compiling as the function is called in the schema itself.
So I added this instead:
skip_authentication? =
field.__private__
|> Keyword.fetch!(:meta)
|> Keyword.get(:skip_authentication, false)
Seems ugly to access __private__
but I couldn’t find any better way. However this still doesn’t work because unfortunately the meta
key is not added unless there’s a meta. It’s a pity that it is not always added, and if no metadata present, have an empty list for meta. As I need a conditional on the presence of meta, I went for this function:
defp get_meta(%{__private__: private}, key, default) do
private
|> Keyword.get(:meta, [])
|> Keyword.get(key, default)
end
Now the problem:
Even if I bypass the Authenticate middleware through a conditional in the middleware/3
callback, it will still execute. I’ve searched for hours but can’t figure out why the middleware would execute. Hence I suspect some magic is happening, Here is the code inside middleware/3
:
def middleware(middleware, field, object) do
skip_authentication? = get_meta(field, :skip_authentication, false)
middleware =
if skip_authentication? do
middleware
else
[Middleware.Authenticate | middleware]
end
case object do
%{identifier: :mutation} ->
middleware ++ [Middleware.HandleChangesetErrors, Middleware.HandleNotFoundErrors]
_ ->
middleware
end
end
But surprisingly the middleware is still called. Tried logging for hours trying to understand why, but really can’t figure this one out.