I'm using Elixir with Phoenix and Absinthe to set up a GraphQL backend.
Ideally, I'd like to have a structure that looks like this:
{
posts {
published {
title
}
draft {
title
}
}
}
To do so, I thought I would need to delegate the posts
field in my schema to an object that responded to published
and draft
. I did this like so:
# In my Schema
field :posts, type: :posts_by_state
# In my Post type definitions
object :post do
# ...
end
object :posts_by_state do
field :published, list_of(:post) do
resolve fn _, _, _ -> ... end
end
field :draft, list_of(:post) do
resolve fn _, _, _ -> ... end
end
end
This didn't work and instead returns null
for the entire posts
field. However, if I changed the posts
field in the schema to include a "blank" resolver, it worked as expected:
field :posts, type: :posts_by_state do
resolve fn _, _, _ -> {:ok, []} end
end
Is this best practice or is there a better way to tell a field to delegate entirely to an object? More generally, is there a better way to structure this?
This answer was provided by benwilson512 on the Elixir forums. Posting here to share the answer
The behavior you’re seeing here is expected, although usually the dummy resolver you’d use is:
field :posts, type: :posts_by_state do
resolve fn _, _, _ -> {:ok, %{}} end
end
If you don’t specify a resolver, Absinthe will use the default resolver, which does a Map.get(parent_value, field_name)
. In your case if the root value is %{}
(which it is by default) then if you don’t specify a posts field resolver Absinthe does Map.get(%{}, :posts)
which of course returns nil
. Since the field returns nil
, no sub fields are executed.
Really though, these seem more like things that should be arguments IE:
{
published: posts(status: PUBLISHED) { title }
draft: posts(status: DRAFT) { title }
}