diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index b260559cb..a9587a031 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -85,13 +85,14 @@ operation. ## Schema Introspection -The schema introspection system is accessible from the meta-fields `__schema` -and `__type` which are accessible from the type of the root of a query -operation. +The schema introspection system is accessible from the meta-fields `__schema`, +`__type` and `__service` which are accessible from the type of the root of a +query operation. ```graphql __schema: __Schema! __type(name: String!): __Type +__service: __Service! ``` Like all meta-fields, these are implicit and do not appear in the fields list in @@ -218,6 +219,15 @@ enum __DirectiveLocation { INPUT_OBJECT INPUT_FIELD_DEFINITION } + +type __Service { + capabilities: [__Capability!]! +} + +type __Capability { + identifier: String! + value: String +} ``` ### The \_\_Schema Type @@ -500,3 +510,76 @@ Fields\: {true}, deprecated arguments are also returned. - `isRepeatable` must return a Boolean that indicates if the directive may be used repeatedly at a single location. + +### The \_\_Service Type + +The `__Service` type is returned from the `__service` meta-field and provides +information about the GraphQL service, most notably about its capabilities. This +type was added after the original release of GraphQL, so older schemas may not +support it. + +Fields\: + +- `capabilities` must return a list of `__Capability` indicating the + capabilities supported by the service. + +### The \_\_Capability Type + +:: A _capability_ describes a feature supported by the GraphQL service but not +directly expressible in the type system. This may include experimental GraphQL +features (such as new syntax or behavior), protocol support (such as GraphQL +over WebSockets), or additional operational metadata (such as release +identifiers). Capabilities may be supplied by the GraphQL implementation, the +service, or both. + +The `__Service.capabilities` field exposes a _capability_ list. A _capability_ +consists of a capability identifier and optionally a string value. + +**Capability identifier** + +A capability identifier is a string value composed of two or more segments +separated by a period (`.`). Each segment must begin with an ASCII letter, and +must contain only ASCII letters, digits and hyphens. These constraints are +inspired by reverse domain name notation to encourage global uniqueness and +collision-resistance. Unlike the domain name system, capability identifiers are +case sensitive. Identifiers beginning with the prefix {"org.graphql."} are +reserved and must not be used outside of official GraphQL Foundation +specifications. Further, identifiers beginning with the prefix +{"org.graphql.http."} are reserved for use by the GraphQL-over-HTTP +specification, and identifiers beginning with the prefix {"org.graphql.rfc."} +are reserved for RFC proposals. + +Identifiers defined by specific projects, vendors, or implementations should +begin with a prefix derived from a DNS name they control (e.g., +{"com.example."}). + +Clients should compare identifiers using exact string equality and should ignore +unknown identifiers. + +Implementers should not change the meaning of capability identifiers; instead, a +new capability identifier should be used when the meaning changes. Implementers +should ensure that capability identifiers remain stable and version-agnostic +where possible; capability versioning, if needed, can be indicated using dot +suffixes (e.g.{ "org.example.capability.v2"}). + +This system enables incremental feature adoption and richer tooling +interoperability, while avoiding tight coupling to specific implementations. + +**Capability value** + +The value assigned to a given capability may either be {null} to simply indicate +the capability is supported, or a string to provide additional information. For +example {"org.graphql.onError"} does not require additional information and thus +uses the value {null}, whereas {"org.graphql.defaultErrorBehavior"} needs the +{value} to indicate which _error behavior_ is the default. + +**Specified capabilities** + +This version of the specification defines the following capabilities: + +- {"org.graphql.defaultErrorBehavior"} - indicates the _default error behavior_ + of the service via the {value}. If not present, must be assumed to be + {"PROPAGATE"}. +- {"org.graphql.onError"} - indicates that the service allows the client to + specify {onError} in a request to indicate the _error behavior_ the service + should use for the request. {value} is {null}. diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index f3e080705..7936eefca 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -4,6 +4,8 @@ A GraphQL service generates a response from a request via execution. :: A _request_ for execution consists of a few pieces of information: + + - {schema}: The schema to use, typically solely provided by the GraphQL service. - {document}: A {Document} which must contain GraphQL {OperationDefinition} and may contain {FragmentDefinition}. @@ -15,6 +17,10 @@ A GraphQL service generates a response from a request via execution. being executed. Conceptually, an initial value represents the "universe" of data available via a GraphQL Service. It is common for a GraphQL Service to always use the same initial value for every request. +- {onError} (optional): The _error behavior_ to apply to the request; see + [Handling Execution Errors](#sec-Handling-Execution-Errors). If {onError} is + provided and its value is not one of {"PROPAGATE"}, {"NO_PROPAGATE"}, or + {"HALT"}, then a _request error_ must be raised. - {extensions} (optional): A map reserved for implementation-specific additional information. @@ -22,6 +28,13 @@ Given this information, the result of {ExecuteRequest(schema, document, operationName, variableValues, initialValue)} produces the response, to be formatted according to the Response section below. +Note: Previous versions of this specification did not define the {onError} +request attribute. Clients can detect support for {onError} by checking for the +{"org.graphql.onError"} capability. If this capability is not present, or if +capabilities themselves are not supported by introspection, then clients should +not include {onError} in the request and must assume the _error behavior_ is +{"PROPAGATE"}. + Implementations should not add additional properties to a _request_, which may conflict with future editions of the GraphQL specification. Instead, {extensions} provides a reserved location for implementation-specific additional @@ -392,13 +405,24 @@ is explained in greater detail in the Field Collection section below. If during {ExecuteSelectionSet()} a _response position_ with a non-null type -raises an _execution error_ then that error must propagate to the parent -response position (the entire selection set in the case of a field, or the -entire list in the case of a list position), either resolving to {null} if -allowed or being further propagated to a parent response position. - -If this occurs, any sibling response positions which have not yet executed or -have not yet yielded a value may be cancelled to avoid unnecessary work. +raises an _execution error_, the error must be added to the {"errors"} list in +the _response_ and then handled according to the _error behavior_ of the +request: + + + +- {"NO\_PROPAGATE"}: The _response position_ must be set to {null}. (The client + is responsible for interpreting this {null} in conjunction with the {"errors"} + list to distinguish error results from intentional {null} values.) +- {"PROPAGATE"}: The _execution error_ must propagate to the parent _response + position_ (the entire selection set in the case of a field, or the entire list + in the case of a list position). The parent position resolves to {null} if + allowed, or else the error is further propagated to a parent response + position. Any sibling response positions that have not yet executed or have + not yet yielded a value may be cancelled to avoid unnecessary work. +- {"HALT"}: The entire _request_ must be cancelled. The {"data"} entry in the + _response_ must be {null}. Any _response position_ that has not yet executed + or has not yet yielded a value may be cancelled to avoid unnecessary work. Note: See [Handling Execution Errors](#sec-Handling-Execution-Errors) for more about this behavior. @@ -823,28 +847,64 @@ MergeSelectionSets(fields): An _execution error_ is an error raised during field execution, value resolution -or coercion, at a specific _response position_. While these errors must be -reported in the response, they are "handled" by producing partial {"data"} in -the _response_. +or coercion, at a specific _response position_. These errors must be added to +the {"errors"} list in the _response_, and are "handled" according to the _error +behavior_ of the request. + +Note: An _execution error_ is distinct from a _request error_ which results in a +response with no {"data"}. + +If a _response position_ resolves to {null} because of an execution error which +has already been 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 _response position_. + +:: The _error behavior_ of a request indicates how an _execution error_ is +handled. It may be specified using the optional {onError} attribute of the +_request_. If omitted, the _default error behavior_ of the service applies. +Valid values for _error behavior_ are {"PROPAGATE"}, {"NO_PROPAGATE"} and +{"HALT"}. + + + +:: The _default error behavior_ of a service is implementation-defined. For +compatibility with existing clients, services should default to {"PROPAGATE"} +which reflects prior behavior. The default error behavior is indicated via the +{"org.graphql.defaultErrorBehavior"} _capability_. + +Note: {"HALT"} is not recommended as the _default error behavior_ because it +prevents generating partial responses which may still contain useful data. + +Regardless of error behavior, if a _response position_ with a non-null type +results in {null} due to the result of {ResolveFieldValue()} then an execution +error must be raised at that position as specified in {CompleteValue()}. -Note: This is distinct from a _request error_ which results in a response with -no data. +The _error behavior_ of a request applies to every _execution error_ raised +during execution. The following sections describe the behavior of each valid +value: -If an execution error is raised while resolving a field (either directly or -nested inside any lists), it is handled as though the _response position_ at -which the error occurred resolved to {null}, and the error must be added to the -{"errors"} list in the response. +**{"NO_PROPAGATE"}** + + + +With {"NO\_PROPAGATE"}, a `Non-Null` _response position_ will have the value +{null} if and only if an error occurred at that position. + +Note: Clients must inspect the {"errors"} list and use the {"path"} of each +error result to distinguish between intentional {null} values and those +resulting from an _execution error_. + +**{"PROPAGATE"}** + +With {"PROPAGATE"}, a `Non-Null` _response position_ must not contain {null} in +the _response_. If the result of resolving a _response position_ is {null} (either due to the result of {ResolveFieldValue()} or because an execution error was raised), and that position is of a `Non-Null` type, then an execution error is raised at that position. The error must be added to the {"errors"} list in the response. -If a _response position_ resolves to {null} because of an execution error which -has already been 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 _response position_. - Since `Non-Null` response positions cannot be {null}, execution errors are propagated to be handled by the parent _response position_. If the parent response position may be {null} then it resolves to {null}, otherwise if it is a @@ -859,3 +919,9 @@ position_ must resolve to {null}. If the `List` type is also wrapped in a If every _response position_ from the root of the request to the source of the execution error has a `Non-Null` type, then the {"data"} entry in the response should be {null}. + +**{"HALT"}** + +With {"HALT"}, execution must cease immediately when the first _execution error_ +is raised. That error must be added to the {"errors"} list, and {"data"} must be +{null}.