@voger gave an awesome answer and I just wanted to post a macro sample based on the accepted question. I'm currently using it to authenticate every field in my schema.
Here's a macro definition:
defmodule MyApp.Notation do
defmacro protected_field(field, type, viewers, opts \\ []) do
{ast, other_opts} =
case Keyword.split(opts, [:do]) do
{[do: ast], other_opts} ->
{ast, other_opts}
{_, other_opts} ->
{[], other_opts}
end
auth_middleware =
if viewers !== :public do
quote do
middleware(MyApp.Middleware.ProtectedField, unquote(viewers))
end
end
quote do
field(unquote(field), unquote(type), unquote(other_opts)) do
unquote(auth_middleware)
middleware(Absinthe.Middleware.MapGet, unquote(field))
unquote(ast)
end
end
end
end
And then inside of your type definitions, you can do this.
import MyApp.Notation
# ...
object :an_object do
protected_field(:description, :string, [User, Admin]) do
middleware(OtherMiddleware)
resolve(fn _, _, _ ->
# Custom Resolve
end)
end
protected_field(:name, :stirng, :public, resolve: &custom_resolve/2)
end
Explanation:
It adds an argument that I call viewers that I just forward to my middleware to check if the user type is correct. In this scenario, I actually have different models that I call Admin and User that I can check the current user against. This is just an example of one way to do it, so your solution might be different. I have a special case for :public fields that are just a passthrough.
This is great because I can inject middleware with the extra argument and forward everything else to the original field definition.
I hope this helps add to the answer.