Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Directive proposal for opting out of null bubbling #1050

Open
wants to merge 5 commits into
base: semantic-non-null
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 95 additions & 1 deletion spec/Section 3 -- Type System.md
Original file line number Diff line number Diff line change
Expand Up @@ -2025,7 +2025,8 @@ by a validator, executor, or client tool such as a code generator.

:: A _built-in directive_ is any directive defined within this specification.

GraphQL implementations should provide the `@skip` and `@include` directives.
GraphQL implementations should provide the `@skip`, `@include` and
`@disableErrorPropagation` directives.

GraphQL implementations that support the type system definition language must
provide the `@deprecated` directive if representing deprecated portions of the
Expand Down Expand Up @@ -2247,3 +2248,96 @@ to the relevant IETF specification.
```graphql example
scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
```

### @disableErrorPropagation

```graphql
directive @disableErrorPropagation on QUERY | MUTATION | SUBSCRIPTION
```

The `@disableErrorPropagation` _built-in directive_ may be provided on query,
mutation and subscription operations, and disables the error propagation
behavior described in [Handling Field Errors](#sec-Handling-Field-Errors) by
treating all Non-Null types as if they were instead Semantic-Non-Null types.

Note: This is useful for clients that still wish to receive sibling fields when
an error on a Non-Null value occurs. Effectively, `@disableErrorPropagation`
enables the client to opt in to handling errors locally; for example, a client
might use this to limit the scope of null propagation to a fragment rather than
the entire field, or to update a normalized store even when an error occurs.

Consider the following schema:

```graphql
type Query {
me: Viewer
}

type Viewer {
username: String!
bestFriend: Viewer!
}
```

If the `bestFriend` field were to return `null`, then the following operation:

```graphql example
query myQuery {
me {
username
bestFriend {
username
}
}
}
```

Would return a result such as:

```json example
{
"errors": [
{
"message": "Value cannot be null",
"locations": [{ "line": 4, "column": 5 }],
"path": ["me", "bestFriend"]
}
],
"data": {
"me": null
}
}
```

However, if we apply the `@disableErrorPropagation` directive to our operation:

```graphql example
query myQuery @disableErrorPropagation {
me {
username
bestFriend {
username
}
}
}
```

The result would contain identical errors, but the "me" field will be populated:

```json example
{
"errors": [
{
"message": "Value cannot be null",
"locations": [{ "line": 4, "column": 5 }],
"path": ["me", "bestFriend"]
}
],
"data": {
"me": {
"username": "billy",
"bestFriend": null
}
}
}
```
12 changes: 9 additions & 3 deletions spec/Section 6 -- Execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -792,14 +792,20 @@ added to the {"errors"} list in the response, the {"errors"} list must not be
further affected. That is, only one error should be added to the errors list per
field.

Since `Non-Null` type fields cannot be {null}, field errors are propagated to be
If the operation provides the `@disableErrorPropagation` directive then
`Non-Null` type fields will become {null} if an error occurs.

If the operation does not provide the `@disableErrorPropagation` directive then
`Non-Null` type fields cannot be {null}, and field errors are propagated to be
handled by the parent field. If the parent field may be {null} then it resolves
to {null}, otherwise if it is a `Non-Null` type, the field error is further
propagated to its parent field.

If a `List` type wraps a `Non-Null` type, and one of the elements of that list
If a `List` type wraps a `Non-Null` type, the operation does not provide the
`@disableErrorPropagation` directive, and one of the elements of that list
resolves to {null}, then the entire list must resolve to {null}. If the `List`
type is also wrapped in a `Non-Null`, the field error continues to propagate
type is also wrapped in a `Non-Null` and the operation does not provide the
`@disableErrorPropagation` directive, the field error continues to propagate
upwards.

If all fields from the root of the request to the source of the field error
Expand Down