diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 3ac7c7e60..ff6230b15 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -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 diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index d32b08566..7f18f1df7 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -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** @@ -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 diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index 3054a9f6c..50b7d5a19 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -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 { @@ -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 } @@ -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 @@ -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 @@ -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. diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index f357069f9..dc0a63681 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -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}.