diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index b260559cb..7ded25024 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -85,11 +85,12 @@ 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 `__service`, +`__schema` and `__type` which are accessible from the type of the root of a +query operation. ```graphql +__service: __Service! __schema: __Schema! __type(name: String!): __Type ``` @@ -124,6 +125,11 @@ are the full set of type system definitions providing schema introspection, which are fully defined in the sections below. ```graphql +type __Service { + capabilities: [String!]! + defaultErrorBehavior: __ErrorBehavior! +} + type __Schema { description: String types: [__Type!]! @@ -164,6 +170,12 @@ enum __TypeKind { NON_NULL } +enum __ErrorBehavior { + NO_PROPAGATE + PROPAGATE + HALT +} + type __Field { name: String! description: String @@ -220,6 +232,124 @@ enum __DirectiveLocation { } ``` +### 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 strings indicating the capabilities + supported by the service. +- `defaultErrorBehavior` must return the _default error behavior_ of the service + using one of the values of the `__ErrorBehavior` enum: + - {"NO_PROPAGATE"} + - {"PROPAGATE"} + - {"HALT"} + +**Capabilities** + +As GraphQL becomes more feature rich, clients need to understand the features +that a service supports so that they only send compatible requests; the +`__Service.capabilities` field reveals these capabilities. + +Note: Prior to the introduction of the capabilities system, a client would +either require out-of-band communication to discover the capabilities of a +schema, or would need to perform multiple introspection phases determining the +fields available in introspection in order to perform feature discovery. + +Capabilities may be supplied by the GraphQL implementation, by the service, or +both. + +A individual capability is described by a string, {CapabilityString}, inspired +by reverse domain name notation to ensure globally unique and +collision-resistant identifiers. A capability string must be composed of two or +more {CompatibilitySegment}, separated by a period (`.`). A {CapabilitySegment} +is a non-empty string composed only from ASCII letter (`[a-zA-Z]`), digits +(`[0-9]`), or hyphens (`-`); it must start with an ASCII letter and must not +terminate with a hyphen. + +CapabilityString :: + +- CapabilityString . CapabilitySegment +- CapabilitySegment . CapabilitySegment + +CapabilitySegment :: + +- CapabilitySegmentStart +- CapabilitySegmentStart CapabilitySegmentContinue\* CapabilitySegmentEnd + +CapabilitySegmentStart :: Letter + +CapabilitySegmentContinue :: + +- Letter +- Digit +- `-` + +CapabilitySegmentEnd :: + +- Letter +- Digit + +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 use string equality to check for known identifiers, 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 strings 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. + +Implementers of earlier versions of this specification may choose to implement +the capabilities system, but when doing so they must not include capabilities +that they do not support. + +Implementers of this version of this specification must include the following +capabilities: + +- {"org.graphql.scalar.specifiedBy"} - indicates the ability to request the + _scalar specification URL_ of a scalar via the `__Type.specifiedBy` + introspection field +- {"org.graphql.directive.repeatable"} - indicates support for repeatable + directive and the related `__Directive.isRepeatable` introspection field +- {"org.graphql.schema.description"} - indicates the ability to request a + description of the schema via the `__Schema.description` introspection field +- {"org.graphql.deprecation.inputValues"} - indicates support for deprecating + input values along with the related introspection schema coordinates: + - `__Directive.args(includeDeprecated:)`, + - `__Field.args(includeDeprecated:)`, + - `__Type.inputFields(includeDeprecated:)`, + - `__InputValue.isDeprecated`, and + - `__InputValue.deprecationReason`. +- {"org.graphql.inputObject.oneOf"} - indicates support for OneOf Input Objects + and the related introspection field `__Type.isOneOf` +- {"org.graphql.errorBehavior"} - indicates that the + `__Service.defaultErrorBehavior` field exists, which indicates the the + _default error behavior_ of the service + +If the schema, implementation, and service support the subscription operation, +the {"org.graphql.subscription"} capability should be included. + +If the service accepts the {onError} request parameter, the +{"org.graphql.onError"} capability should be included. If it is not included, +clients should infer the default will be used for all requests. + ### The \_\_Schema Type The `__Schema` type is returned from the `__schema` meta-field and provides all diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index f3e080705..8419eb789 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,62 @@ 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. For new services, {"NO_PROPAGATE"} is +recommended. The default error behavior is indicated via the +`defaultErrorBehavior` field of the `__Service` introspection type. + +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 +917,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}.