Graphql-js: What is the best approach to manage custom user errors?

Created on 8 Nov 2016  路  5Comments  路  Source: graphql/graphql-js

I am very interested to know how to talk with the client with custom errors.

For example, if you create a new user and the user email already exists on the database, the API has to be able to reply to the client with a custom error. What is the best approach to achieve this?
Maybe, some of you start thinking that this has to be controlled by the client UI, but sometimes, an API is used by different clients or third-party apps. So, it is very important to detect all the errors on the API as well.

At this moment, I manage the custom errors by this way, but I am not pretty sure if it is the best approach.

mutation {
  signUp(email: "[email protected]", password: "123") {
    token
    errors {
      key
      value
    }
  }
}
"data": {
  "signUp": {
    "token": null,
    "errors": [{ "key": "user.exists", "value": "There is already a user with this email." }]
  }
}

If you want to share your approach to achieve this, I will be very happy to read about it.

I think we should consider this to add to the documentation on http://graphql.org/graphql-js/. In my opinion, it is very important to manage all the errors properly to build good GraphQL APIs.

Thank you very much.

Most helpful comment

I like your approach @jferrettiboke

I think of errors in two categories:

  1. Something went wrong and part of a query/operation couldn't be fulfilled.
  2. The user did something wrong and needs to be provided feedback.

Errors in GraphQL are designed for the first of those cases, and while they can often suffice for the second case - as soon as you need to supply more sophisticated information I think GraphQL errors can fall short.

I like to start with what I want the user experience to be when there's an error, and then work backwards to the API design to make sure I'm including the relevant information. For example, maybe just displaying some text is adequate, but you might also want to display something more into the UI - maybe some element on the screen needs to be highlighted or animate. Maybe you want to show more than just text: but also an illustrative image and a link for more information on what happened. The more you go down this path the more you realize that what you're actually describing is _data_ for a very real supported case in your API, and not an _error_ for an unexpected case.

I think it's easy to start off by thinking of these as errors since the system-engineer in all of us wants to think of any imperfect input as unexpected and erroneous, but the experience designers in us need to account for all real scenarios in our products and the APIs that support them. So I think building this sort of error into the API directly to make it easy for products to leverage them (as your instincts have led you to) is actually a good idea.

All 5 comments

Hey, I wrote up an RFC for an error path here: https://github.com/facebook/graphql/pull/230

That would be a standard replacement for your error "key", and you can get it really easily from GraphQL.js errors already since this PR: https://github.com/graphql/graphql-js/pull/396

I like your approach @jferrettiboke

I think of errors in two categories:

  1. Something went wrong and part of a query/operation couldn't be fulfilled.
  2. The user did something wrong and needs to be provided feedback.

Errors in GraphQL are designed for the first of those cases, and while they can often suffice for the second case - as soon as you need to supply more sophisticated information I think GraphQL errors can fall short.

I like to start with what I want the user experience to be when there's an error, and then work backwards to the API design to make sure I'm including the relevant information. For example, maybe just displaying some text is adequate, but you might also want to display something more into the UI - maybe some element on the screen needs to be highlighted or animate. Maybe you want to show more than just text: but also an illustrative image and a link for more information on what happened. The more you go down this path the more you realize that what you're actually describing is _data_ for a very real supported case in your API, and not an _error_ for an unexpected case.

I think it's easy to start off by thinking of these as errors since the system-engineer in all of us wants to think of any imperfect input as unexpected and erroneous, but the experience designers in us need to account for all real scenarios in our products and the APIs that support them. So I think building this sort of error into the API directly to make it easy for products to leverage them (as your instincts have led you to) is actually a good idea.

Thank you to both of you, guys.

I am more with @leebyron's answer than @stubailo's answer for this type of question that I asked.

What do you think about adding examples with these type of errors on the docs (Best Practices section)? I think is very important to write about "the two type of errors" and its differences to have a good understanding about throw errors for an unexpected case and throw errors described as API's data. If I asked this type of question, maybe more people have it in mind.
Developers love to see standards (or the best approach so far) over a specific thing to trust and feel safety with the implementation. I suggest to cover this topic on the documentation.

Great suggestion - I opened a task for that

@stubailo Sashko, is the RFC you wrote here supposed to be written as part of our schema? facebook/graphql#230

On my mutation, should I be adding to the schema the Error property with message and path on it?

Was this page helpful?
0 / 5 - 0 ratings