Allow mutations to have custom error types

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

Problem to solve

All our mutation responses have an errors field inherited from BaseMutation, but this has the unfortunate type of [Types::STRING_TYPE], which is basically the lowest common denominator of error information we might wish to present to users.

Errors can (and perhaps in some cases should) be much richer, including for example filenames in merge conflict errors, or duplicate upload errors, missing permission names in permission violations, field names in validation errors. Clients are missing out on richer experiences by using an impoverished error type.

Intended users

User experience goal

Developers can provide richer failure information in mutations, and clients can use this to provide more than a message to users.

Proposal

We allow users to override the type of the error.

We could do this as below:

class BaseMutations < Mutation
  def self.inherited(child_class)
    tp = TracePoint.new(:end) do |t|
      if child_class == t.self
        t.disable
        child_class.field :errors, [child_class.error_type],  null: false, description: child_class.error_description
      end
    end
    tp.enable
  end

  def self.error_type(type = GraphQL::STRING_TYPE)
    @error_type = type
  end

  def self.error_description(desc = 'Errors encountered during execution of the mutation')
    @description ||= desc
  end
end

class MuMutation < BaseMutation
  error_type MyCustomErrorType
end

We cannot just use the inherited hook, since that runs at the start of the class definition, before the child type has had the chance to provide any overrides. The use of TracePoint like this is somewhat ugly, but has been confirmed to work.

Documentation

This would need to be described in our API styleguide.

Availability & Testing

What does success look like, and how can we measure that?

When we can provide richer errors than simple error messages.

Is this a cross-stage feature?

This affects all stages using GraphQL (all of them).

Links / references

Edited by 🤖 GitLab Bot 🤖