sandorbedo
How to return partial responses in Absinthe?
Hi,
How should an Absinthe.Resolution struct look like when I want to return both data and errors from Absinthe?
This is now allowed by the GraphQL spec., but whenever I put something into the errors field of the Absinthe.Resolution struct, the data part of the response disappears from the response. This is what I try to do in a middleware without much success:
def call(resolution, params) do
resolution
|> Absinthe.Resolution.put_result({:error, params.errors})
|> Absinthe.Resolution.put_result({:ok, params.data})
end
…and in the handler function I simply return {:middleware, MyMiddleware, %{data: ..., errors: ...}}. It doesn’t make any difference when I try to manipulate the resolution struct directly, not via put_result/2.
What’s wrong with this approach?
Is it even possible to return data and errors in a single response using Absinthe?
Most Liked
benwilson512
Hi @sandorbedo this is a common misreading of the spec. This is talking about the overall response shape, not the resolution of any specific field. Absinthe absolutely lets you do the following:
{
fieldwithNoError
fieldWithError
}
fieldwithNoError will return a result even if fieldWithError returns an error. What you’re asking about is for an individual field to return both data and errors. That’s governed by this section of the spec: Handling Field Errors which unambiguously states:
If a field error is raised while resolving a field, it is handled as though the field returned null,
and the error must be added to the “errors” list in the response.
Absinthe is compliant here.
EDIT: A quick check of the 2025 draft shows that this remains unchanged in the latest draft too: GraphQL
benwilson512
To answer your last question first:
You absolutely can:
object :hero do
field :id, :id
field :name, :string, resolve: &name_or_error/3
end
defp name_or_error(parent, _, _) do
case Map.fetch(parent, :name) do
{:ok, name} -> {:ok, name}
:error -> {:error, "Name for character with ID #{parent.id} could not be fetched."}
end
end
It’s worth pointing out as well that in your example what is the path of the error? It’s "path": ["hero", "heroFriends", 1, "name"]. This means that the error was raised while resolving this field. If it was raised from the heroFriends field you would see the path simply be ["hero", "heroFriends"].
This is not correct. Every field has a resolver. Every field is “resolved”. Objects do not have resolvers at all, only fields do. More to the point, the spec is talking about the “process” of resolving a field, which isn’t implementation specific. See GraphQL. Every field goes through this execution and resolution process recursively.








