Skip to content

Commit 9209832

Browse files
committed
Add error behaviors to the spec
1 parent a4fe27e commit 9209832

File tree

2 files changed

+79
-25
lines changed

2 files changed

+79
-25
lines changed

spec/Section 6 -- Execution.md

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,15 @@ A GraphQL service generates a response from a request via execution.
1515
being executed. Conceptually, an initial value represents the "universe" of
1616
data available via a GraphQL Service. It is common for a GraphQL Service to
1717
always use the same initial value for every request.
18+
- {errors} (optional): The _error behavior_ that is desired, see
19+
[Handling Execution Errors](#sec-Handling-Execution-Errors).
1820

1921
Given this information, the result of {ExecuteRequest(schema, document,
2022
operationName, variableValues, initialValue)} produces the response, to be
21-
formatted according to the Response section below.
23+
formatted according to the Response section below. The value of {errors} is
24+
referenced by the [Handling Execution Errors](#sec-Handling-Execution-Errors)
25+
section only, so we do not complicate the algorithms by passing it through every
26+
call.
2227

2328
Note: GraphQL requests do not require any specific serialization format or
2429
transport mechanism. Message serialization and transport mechanisms should be
@@ -815,38 +820,81 @@ MergeSelectionSets(fields):
815820
### Handling Execution Errors
816821

817822
An _execution error_ is an error raised from a particular field during value
818-
resolution or coercion. While these errors should be reported in the response,
819-
they are "handled" by producing a partial response.
823+
resolution or coercion. These errors should be reported in the response and are
824+
"handled" according to the selected _error behavior_.
820825

821-
Note: This is distinct from a _request error_ which results in a response with
822-
no data.
826+
Note: An _execution error_ is distinct from a _request error_ which results in a
827+
response with no data.
823828

824-
If an execution error is raised while resolving a field (either directly or
825-
nested inside any lists), it is handled as though the position at which the
826-
error occurred resulted in {null}, and the error must be added to the {"errors"}
827-
list in the response.
829+
If the result of resolving a field is {null}, and that field is of a `Non-Null`
830+
type, then an execution error is raised by the field.
828831

829-
If the result of resolving a _response position_ is {null} (either due to the
830-
result of {ResolveFieldValue()} or because an execution error was raised), and
831-
that position is of a `Non-Null` type, then an execution error is raised at that
832-
position. The error must be added to the {"errors"} list in the response.
832+
If a `List` type wraps a `Non-Null` type, and one of the elements of that list
833+
resolves to {null}, then an execution error is raised by the list item.
834+
835+
:: The _error behavior_ is the way in which the request wishes for errors to be
836+
handled. Valid values are {"PROPAGATE"}, {"NO_PROPAGATE"} and {"ABORT"}; their
837+
respective behaviors are detailed below.
838+
839+
Implementations are free to choose the default value to use if _error behavior_
840+
is not specified. It is recommended this is {"NO_PROPAGATE"} for newly created
841+
schemas, but {"PROPAGATE"} should be used for existing schemas since that was
842+
the implicit behavior in previous versions of this specification.
843+
844+
Note: {"ABORT"} is not recommended as the default error behavior because it
845+
makes clients less resilient to errors. GraphQL enables partial responses so
846+
that the end user can still see some useful data even when something goes wrong
847+
on the server.
833848

834-
If a _response position_ returns {null} because of an execution error which has
849+
If an execution error is raised from a response position, it must be added to
850+
the {"errors"} list in the _response_.
851+
852+
If the response position returns {null} because of an execution error which has
835853
already been added to the {"errors"} list in the response, the {"errors"} list
836854
must not be further affected. That is, only one error should be added to the
837-
errors list per _response position_.
855+
errors list per response position.
838856

839-
Since `Non-Null` response positions cannot be {null}, execution errors are
840-
propagated to be handled by the parent _response position_. If the parent
841-
response position may be {null} then it resolves to {null}, otherwise if it is a
842-
`Non-Null` type, the execution error is further propagated to its parent
843-
_response position_.
857+
Execution errors are handled according to the selected _error behavior_, as
858+
detailed below:
844859

845-
If a `List` type wraps a `Non-Null` type, and one of the elements of that list
846-
resolves to {null}, then the entire list must resolve to {null}. If the `List`
847-
type is also wrapped in a `Non-Null`, the execution error continues to propagate
848-
upwards.
860+
**PROPAGATE**
861+
862+
This is the traditional error handling approach in which errors are "handled" by
863+
producing a partial response whilst ensuring that {null} may not occur in a
864+
`Non-Null` position.
865+
866+
If an execution error is raised while resolving a nullable response position, it
867+
is handled as though the response position returned {null} (and as stated above,
868+
the error must be added to the {"errors"} list in the response).
869+
870+
Since `Non-Null` response positions cannot be {null}, execution errors that
871+
occur in `Non-Null` response positions are propagated to be handled by the
872+
parent position. If the parent response position may be {null} then it resolves
873+
to {null}, otherwise if it is a `Non-Null` type, the execution error is further
874+
propagated to its parent response position.
849875

850876
If all response positions from the root of the request to the source of the
851877
execution error return `Non-Null` types, then the {"data"} entry in the response
852-
should be {null}.
878+
is made {null}.
879+
880+
**NO_PROPAGATE**
881+
882+
This is the modern error handling approach in which errors are "handled" by
883+
producing a partial response _without_ propagating errors to conform to
884+
`Non-Null` positions.
885+
886+
Note: With this error behavior, the client is expected to honour the {"errors"}
887+
in the _response_ and prevent developers from reading a {null} produced by an
888+
error. One approach for clients to to prevent a {null} produced by an error from
889+
being read is to raise an error on the client when the errored response
890+
position's data is accessed.
891+
892+
**ABORT**
893+
894+
This error handling approach terminates the request when an execution error is
895+
raised in any response position by setting the {"data"} entry in the response to
896+
{null}.
897+
898+
It is not recommended to default to {"ABORT"}, however it can be useful for
899+
certain classes of clients, such as ad-hoc scripts, that do not know how to
900+
handle errors and thus wish to abort and fail the moment any error occurs.

spec/Section 7 -- Response.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ key `data`. The value of this entry is described in the "Data" section. If the
2626
request failed before execution, due to a syntax error, missing information, or
2727
validation error, this entry must not be present.
2828

29+
If the request included execution, raised any errors, and the _error behavior_
30+
was not {"PROPAGATE"} then the response map must contain an entry with key
31+
`errors`. Otherwise, inclusion of the `errors` key is permitted but not
32+
recommended. The value of this key, if present, must be that of the _error
33+
behavior_.
34+
2935
The response map may also contain an entry with key `extensions`. This entry, if
3036
set, must have a map as its value. This entry is reserved for implementers to
3137
extend the protocol however they see fit, and hence there are no additional

0 commit comments

Comments
 (0)