Skip to content

Commit

Permalink
Merge pull request #1215 from maartenvanvliet/issues/925-error-extens…
Browse files Browse the repository at this point in the history
…tions-spec-compliance

Place extra errors in extensions field
  • Loading branch information
benwilson512 authored Jun 29, 2023
2 parents fab6ac9 + 32db847 commit 555aeb8
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 14 deletions.
39 changes: 26 additions & 13 deletions lib/absinthe/phase/document/result.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ defmodule Absinthe.Phase.Document.Result do
use Absinthe.Phase

@spec run(Blueprint.t() | Phase.Error.t(), Keyword.t()) :: {:ok, map}
def run(%Blueprint{} = bp, _options \\ []) do
result = Map.merge(bp.result, process(bp))
def run(%Blueprint{} = bp, options \\ []) do
result = Map.merge(bp.result, process(bp, options))
{:ok, %{bp | result: result}}
end

defp process(blueprint) do
defp process(blueprint, opts) do
result =
case blueprint.execution do
%{validation_errors: [], result: nil} ->
Expand All @@ -25,20 +25,20 @@ defmodule Absinthe.Phase.Document.Result do
{:validation_failed, errors}
end

format_result(result)
format_result(result, opts)
end

defp format_result({:ok, {data, []}}) do
defp format_result({:ok, {data, []}}, _) do
%{data: data}
end

defp format_result({:ok, {data, errors}}) do
errors = errors |> Enum.uniq() |> Enum.map(&format_error/1)
defp format_result({:ok, {data, errors}}, opts) do
errors = errors |> Enum.uniq() |> Enum.map(&format_error(&1, opts))
%{data: data, errors: errors}
end

defp format_result({:validation_failed, errors}) do
errors = errors |> Enum.uniq() |> Enum.map(&format_error/1)
defp format_result({:validation_failed, errors}, opts) do
errors = errors |> Enum.uniq() |> Enum.map(&format_error(&1, opts))
%{errors: errors}
end

Expand Down Expand Up @@ -109,12 +109,13 @@ defmodule Absinthe.Phase.Document.Result do
defp field_name(%{alias: name}), do: name
defp field_name(%{name: name}), do: name

defp format_error(%Phase.Error{locations: []} = error) do
defp format_error(%Phase.Error{locations: []} = error, opts) do
error_object = %{message: error.message}
Map.merge(error.extra, error_object)

merge_error_extensions(error_object, error.extra, opts)
end

defp format_error(%Phase.Error{} = error) do
defp format_error(%Phase.Error{} = error, opts) do
error_object = %{
message: error.message,
locations: Enum.flat_map(error.locations, &format_location/1)
Expand All @@ -126,7 +127,19 @@ defmodule Absinthe.Phase.Document.Result do
path -> Map.put(error_object, :path, path)
end

Map.merge(Map.new(error.extra), error_object)
merge_error_extensions(error_object, error.extra, opts)
end

defp merge_error_extensions(error_object, extra, _opts) when extra == %{} do
error_object
end

defp merge_error_extensions(error_object, extra, opts) do
if opts[:spec_compliant_errors] do
Map.merge(%{extensions: extra}, error_object)
else
Map.merge(extra, error_object)
end
end

defp format_location(%{line: line, column: col}) do
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
defmodule Elixir.Absinthe.Integration.Execution.Resolution.ExtraErrorFieldsTest do
use Absinthe.Case, async: true
alias Absinthe.Pipeline
alias Absinthe.Phase

@query """
mutation { failingThing(type: WITH_CODE) { name } }
"""

test "scenario #1" do
test "extra fields places in errors list" do
assert {:ok,
%{
data: %{"failingThing" => nil},
Expand All @@ -19,4 +21,51 @@ defmodule Elixir.Absinthe.Integration.Execution.Resolution.ExtraErrorFieldsTest
]
}} == Absinthe.run(@query, Absinthe.Fixtures.Things.MacroSchema, [])
end

test "extra fields placed in extensions" do
pipeline =
Pipeline.for_document(Absinthe.Fixtures.Things.MacroSchema)
|> Pipeline.replace(
Phase.Document.Result,
{Phase.Document.Result, spec_compliant_errors: true}
)

assert {:ok,
%{
result: %{
data: %{"failingThing" => nil},
errors: [
%{
message: "Custom Error",
path: ["failingThing"],
locations: [%{column: 12, line: 1}],
extensions: %{code: 42}
}
]
}
}, _} = Pipeline.run(@query, pipeline)
end

@query """
mutation { failingThing(type: MULTIPLE) { name } }
"""
test "when no extra fields, extensions field is omitted" do
pipeline =
Pipeline.for_document(Absinthe.Fixtures.Things.MacroSchema)
|> Pipeline.replace(
Phase.Document.Result,
{Phase.Document.Result, spec_compliant_errors: true}
)

assert {:ok,
%{
result: %{
data: %{"failingThing" => nil},
errors: [
%{locations: [%{column: 12, line: 1}], message: "one", path: ["failingThing"]},
%{locations: [%{column: 12, line: 1}], message: "two", path: ["failingThing"]}
]
}
}, _} = Pipeline.run(@query, pipeline)
end
end

0 comments on commit 555aeb8

Please sign in to comment.