Move Plug error to a GraphQL response

I am using Absinthe.Plug with Phoenix to create a GraphQL API. I have a couple plugs that run and modify the Plug.Conn before Absinthe.Plug processes the request. What I am wondering is, what is the best way to have an error from one of these early Plugs move to the errors field of the graphql response? I add the errors to the absinthe context like:

Absinthe.Plug.assign_context(conn, :errors, [%{message: error, field: field} | errors])

(errors comes from the existing context so I can add more than one error) so I know they are available later in resolvers or other Absinthe processing.

I know that returning {:error, "An error happened"} from a resolver will return an errors field in the response.

I tried a Absinthe.Plugin like:

defmodule PhWeb.Plugins.HandleErrors do
  @behaviour Absinthe.Plugin

  # Move errors from context into execution (resolution)
  def after_resolution(%{context: context} = execution) do
    case Map.get(context, :errors) do
      nil ->
        execution
      errors ->
        Map.put(execution, :errors, Map.get(execution, :errors, []) ++ errors)
    end
  end

  def before_resolution(execution), do: execution
  def pipeline(next_pipeline, _), do: next_pipeline
end

figuring it would set errors on the resolution and those would end up in the GraphQL response but that doesn’t seem to be the case. Is there a way to move errors like this?

1 Like

It might be easier to work backward from your goal :thinking: Do you have a theoretical example of the JSON payload you’d like your server to return?

1 Like

If I return :{ok, "An error occurred"} from a resolver I get a response like:

{
  "data": {
    "me": null
  },
  "errors": [
    {
      "locations": [
        {
          "column": 5,
          "line": 2
        }
      ],
      "message": "An error occurred",
      "path": [
        "me"
      ]
    }
  ]
}

That’s the response I am looking for with the error generated in my early plug rather than returned from a reslover. I thought there might be a place in the Absinthe pipeline to add thees errors to the response. I guess I can add a Plug that runs after the absinthe Plug and add errors to the response after Absinthe is done processing.

I got this working by adding errors to the Absinthe context in my early plugs using: Absinthe.Plug.assign_context() and extending the Absinthe pipeline with a Phase that moves errors from the context into the result.

The error spec for GraphQL is pretty minimal, if the error is happening before absinthe is it something more like a general server error?

Chances are you could return the JSON in the right shape up front and never enter the absinthe pipeline.