Graphql-ruby: Adding multiple errors to the errors field.

Created on 22 Mar 2017  路  9Comments  路  Source: rmosolgo/graphql-ruby

Hi there,

First of all, great job on this library! It is a very useful tool and an extremely valuable contribution to the community.

Just a quick question - I am aware how it is possible to return a GraphQL::ExecutionError from the resolve function to attach an error to the errors array in the response. However, I can't work out a way to add multiple errors, e.g. one entry in the array for each validation error generated by Rails. I know I could just .join(', ') the messages but I feel that creating a separate array entry for each would be cleaner.

Is there a way to do this or is it not currently supported?

I am not very keen on adding a custom errors field to my schema, I'd prefer to put all errors in the top-level field as suggested by the GraphQL spec and simply return a null data entry when a mutation fails.

Thanks!

Most helpful comment

Hi! Glad you're enjoing it!

The ctx argument to resolve has an add_error method which can be used to add ExecutionErrors to the response. For example:

resolve ->(obj, args, ctx) {
  # ...
  ctx.add_error(GraphQL::ExecutionError.new("Oops, something went wrong"))
  ctx.add_error(GraphQL::ExecutionError.new("Oops, something went VERY wrong"))
  nil
}

Sorry that's not well documented! I'll try to revisit it soon. Does that work in your case?

All 9 comments

Hi! Glad you're enjoing it!

The ctx argument to resolve has an add_error method which can be used to add ExecutionErrors to the response. For example:

resolve ->(obj, args, ctx) {
  # ...
  ctx.add_error(GraphQL::ExecutionError.new("Oops, something went wrong"))
  ctx.add_error(GraphQL::ExecutionError.new("Oops, something went VERY wrong"))
  nil
}

Sorry that's not well documented! I'll try to revisit it soon. Does that work in your case?

Thanks! It works a treat and is exactly what I was looking for.

I needed this as well, thanks!

@rmosolgo, please help me to understand how to add multiple errors in the new syntax. It is still not documented :(

@rmosolgo same here!

@nadiyaka did you figure it out?

This was the top result from a search for "graphql ruby return multiple errors", so in case anyone else ends up looking for how to do this, here is a trivial example that seems to (roughly) work in 1.10:

  def resolve(arg1:, arg2:)
    {
      result: MyAction.execute(arg1, arg2) # raises a single error of a custom type wrapping validation errors
    }
  rescue ValidationFailure => failure
    failure.errors.each do |error|
      context.add_error(
        GraphQL::ExecutionError.new(
          error.message,
          path: error.path,
          extensions: error.extensions
        )
      )
    end
  end
end

Note that this is a trivial example with some less-than-best practices. The important thing to note is that the GraphQL::Schema::Mutation (in fact any GraphQL::Schema::Resolver) has an attr_accessor for the context, which still has the add_error method.

[Edit: Added params to MyAction.execute.]

This was the top result from a search for "graphql ruby return multiple errors", so in case anyone else ends up looking for how to do this, here is a trivial example that seems to (roughly) work in 1.10:

is there anyway to use a wrapper as we are going to use a lot this rescue in every resolver? , in the old graphql we used
something like

resolve RescueFrom.new lambda { |_, args, ctx|

but am dumb and tired can't see how to apply it now

@pablosky : See the rescue_from mentioned on the Error Handling page. It basically gets defined at the schema level.

I wrote a helper that manually formats array errors correctly in 1.11:

# In GraphQL Ruby, an array of all errors nullifies the entire array result
# This manually fixes the behavior so that errors are reported with their path,
# and their array position is nullified.
def self.map_array_errors(array, context)
  array.each_with_index.map do |item, idx|
    item = yield(item) if block_given?
    if item.is_a?(GraphQL::ExecutionError)
      item.path = [context[:current_path], idx].flatten
      context.add_error(item)
      nil
    else
      item
    end
  end
end
Was this page helpful?
0 / 5 - 0 ratings