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?
First Post!
sandorbedo
I believe this fixes the problem in Absinthe, but I’m not sure why was the result nulled out when there were errors in the response.
diff --git a/lib/absinthe/phase/document/execution/resolution.ex b/lib/absinthe/phase/document/execution/resolution.ex
index f5b01e5c..8b97cb35 100644
--- a/lib/absinthe/phase/document/execution/resolution.ex
+++ b/lib/absinthe/phase/document/execution/resolution.ex
@@ -269,13 +269,6 @@ defmodule Absinthe.Phase.Document.Execution.Resolution do
bp_field = put_in(bp_field.schema_node.type, full_type)
- # if there are any errors, the value is always nil
- value =
- case errors do
- [] -> value
- _ -> nil
- end
-
errors = maybe_add_non_null_error(errors, value, full_type)
value
diff --git a/lib/absinthe/phase/document/result.ex b/lib/absinthe/phase/document/result.ex
index 651555b7..f07abefc 100644
--- a/lib/absinthe/phase/document/result.ex
+++ b/lib/absinthe/phase/document/result.ex
@@ -42,7 +42,18 @@ defmodule Absinthe.Phase.Document.Result do
%{errors: errors}
end
- defp data(%{errors: [_ | _] = field_errors}, errors), do: {nil, field_errors ++ errors}
+ defp data(%{errors: [_ | _] = field_errors} = input, errors) do
+ {value, more_errors} =
+ if input.value != nil do
+ input
+ |> Map.put(:errors, [])
+ |> data(errors)
+ else
+ {nil, []}
+ end
+
+ {value, field_errors ++ errors ++ more_errors}
+ end
# Leaf
defp data(%{value: nil}, errors), do: {nil, errors}
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.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









