53 lines
2.5 KiB
Markdown
53 lines
2.5 KiB
Markdown
|
# GraphQL Errors
|
||
|
|
||
|
The GraphQL spec describes a top-level errors key
|
||
|
(https://facebook.github.io/graphql/June2018/#sec-Errors). It is useful
|
||
|
for fatal errors that prevent an operation from returning data. The Ruby
|
||
|
GraphQL gem automatically populates `errors` whenever there is a
|
||
|
synatactical error, or when a resolver returns a `GraphQL::ExecutionError`.
|
||
|
|
||
|
## Mutation Errors
|
||
|
|
||
|
For fatal errors (like lack of permission), we return a
|
||
|
`GraphQL::ExecutionError` (populating the top-level errors field).
|
||
|
|
||
|
There are a number of reasons why we wouldn't want to use the top-level
|
||
|
errors field for user-facing errors (like validations).
|
||
|
|
||
|
* There are potentially many validation errors per model attribute, but
|
||
|
once the system encounters one `GraphQL::ExecutionError` it will stop
|
||
|
processing that mutation.
|
||
|
* Apollo client (and probably other GraphQL clients) have special treatment
|
||
|
for the top-level errors field which is probably not ideal for
|
||
|
displaying validation errors to the user.
|
||
|
* Validation errors are meant to be displayed to the user, whereas system
|
||
|
errors are not likely to be shown.
|
||
|
|
||
|
Instead, the common solution for handling these types of errors is to
|
||
|
include an `errors` key as part of the mutation response. There doesn't
|
||
|
yet seem to be any consensus around a common format for the shape of these
|
||
|
errors.
|
||
|
|
||
|
The primary source of validation errors in Canvas are the rails validations
|
||
|
defined in our models. The simplest way to expose those would be to add an
|
||
|
`errors` key that is a list of {attribute, message} pairs. Some
|
||
|
validations do not directly correspond to a GraphQL field (either because
|
||
|
it's not a field exposed in GraphQL, or the attribute has been renamed), so
|
||
|
we'll need way to either map those attribute names appropriately, or return
|
||
|
a generic object-wide error message (generic error messages could be
|
||
|
indicated by any error with a null attribute).
|
||
|
|
||
|
A different way to express errors would be to have a mutation-specific
|
||
|
error type for each mutation. The error shape could then look something
|
||
|
like {attribute1 => [message1, message2], attribute2 => [message1], ...}.
|
||
|
The big downside to this approach is that consuming this form of errors
|
||
|
would require enumerating all possible attributes at query time which feels
|
||
|
burdensome.
|
||
|
|
||
|
## A Note on Inst UI
|
||
|
|
||
|
Inst UI form components take a "message" attribute that is used to display
|
||
|
errors. We will want some kind of general purpose helper function that
|
||
|
extracts the validation errors from a mutation response and bundles them in
|
||
|
a format more consumable by Instructure UI.
|