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

[WIP] Non-nullable error boundary - interrobang #1046

Closed
wants to merge 1 commit into from
Closed
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
6 changes: 6 additions & 0 deletions spec/Section 2 -- Language.md
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,12 @@ NonNullType :

- NamedType !
- ListType !
- NonNullErrorBoundaryType

NonNullErrorBoundaryType :

- NamedType ! ?
- ListType ! ?

GraphQL describes the types of data expected by arguments and variables. Input
types may be lists of another input type, or a non-null variant of any other
Expand Down
21 changes: 14 additions & 7 deletions spec/Section 3 -- Type System.md
Original file line number Diff line number Diff line change
Expand Up @@ -1787,11 +1787,16 @@ Following are examples of input coercion with various list types and values:
## Non-Null

By default, all types in GraphQL are nullable; the {null} value is a valid
response for all of the above types. To declare a type that disallows null, the
GraphQL Non-Null type can be used. This type wraps an underlying type, and this
type acts identically to that wrapped type, with the exception that {null} is
not a valid response for the wrapping type. A trailing exclamation mark is used
to denote a field that uses a Non-Null type like this: `name: String!`.
response for all of the above types. To declare a type that is not expected to
be null, the GraphQL Non-Null type can be used. This type wraps an underlying
type, and this type acts identically to that wrapped type, with the exception
that {null} is not an expected response for the wrapping type. A Non-Null type
may be an error-boundary in which case the response is allowed to be {null}, but
only with an associated error in the errors array; otherwise {null} is not a
valid value. A trailing exclamation mark is used to denote a field that uses a
Non-Null type like this: `name: String!`, and an additional `?` is used to
indicate that this Non-Null type is an error boundary, like this:
`name: String!?`.

**Nullable vs. Optional**

Expand All @@ -1810,8 +1815,10 @@ always optional and non-null types are always required.
In all of the above result coercions, {null} was considered a valid value. To
coerce the result of a Non-Null type, the coercion of the wrapped type should be
performed. If that result was not {null}, then the result of coercing the
Non-Null type is that result. If that result was {null}, then a _field error_
must be raised.
Non-Null type is that result. If that result was {null}, then: if the Non-Null
is an error boundary then the result of coercing the Non-Null type is {null} but
a _field error_ must be collected; otherwise if the Non-Null is not an error
boundary then a _field error_ must be raised.

Note: When a _field error_ is raised on a non-null value, the error propagates
to the parent field. For more information on this process, see
Expand Down
19 changes: 16 additions & 3 deletions spec/Section 4 -- Introspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ type __Type {
ofType: __Type
# may be non-null for custom SCALAR, otherwise null.
specifiedByURL: String
# must be non-null for NON_NULL, otherwise null.
isErrorBoundary: Boolean
}

enum __TypeKind {
Expand All @@ -168,7 +170,7 @@ type __Field {
name: String!
description: String
args(includeDeprecated: Boolean = false): [__InputValue!]!
type: __Type!
type(includeErrorBoundaries: Boolean! = false): __Type!
isDeprecated: Boolean!
deprecationReason: String
}
Expand Down Expand Up @@ -395,8 +397,13 @@ Fields\:
GraphQL types are nullable. The value {null} is a valid response for field type.

A Non-Null type is a type modifier: it wraps another type instance in the
`ofType` field. Non-null types do not allow {null} as a response, and indicate
required inputs for arguments and input object fields.
`ofType` field. A Non-Null type may opt to be an error boundary, in which case
it indicates that the value is not expected to be null: it will only be null in
the case of an error (either it's own, or one of its children). For error
boundary non-null types, the `null` value will not "bubble". Error boundary
non-null types are only allowed in output positions. Non-null types that are not
error boundaries do not allow {null} as a response, and indicate required inputs
for arguments and input object fields.

The modified type in the `ofType` field may itself be a modified List type,
allowing the representation of Non-Null of Lists. However it must not be a
Expand All @@ -406,6 +413,8 @@ Fields\:

- `kind` must return `__TypeKind.NON_NULL`.
- `ofType` must return a type of any kind except Non-Null.
- `isErrorBoundary` must return true if this Non-Null is an error boundary,
false otherwise.
- All other fields must return {null}.

### The \_\_Field Type
Expand All @@ -422,6 +431,10 @@ Fields\:
{true}, deprecated arguments are also returned.
- `type` must return a `__Type` that represents the type of value returned by
this field.
- Accepts the argument `includeErrorBoundaries` which defaults to {false}. If
{false} then the field will instead return a `__Type` that represents the
type of value returned by this field with all error-boundary non-null type
modifiers removed. This is for backwards compatibility.
- `isDeprecated` returns {true} if this field should no longer be used,
otherwise {false}.
- `deprecationReason` optionally provides a reason why this field is deprecated.
Expand Down
5 changes: 4 additions & 1 deletion spec/Section 6 -- Execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,10 @@ CompleteValue(fieldType, fields, result, variableValues):
- Let {innerType} be the inner type of {fieldType}.
- Let {completedResult} be the result of calling {CompleteValue(innerType,
fields, result, variableValues)}.
- If {completedResult} is {null}, raise a _field error_.
- If {completedResult} is {null}:
- If {fieldType} is an error boundary, collect a _field error_ and return
{null}.
- Otherwise, raise a _field error_.
- Return {completedResult}.
- If {result} is {null} (or another internal value similar to {null} such as
{undefined}), return {null}.
Expand Down