diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 79953a4e0..89c1c5fbd 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -328,7 +328,7 @@ GraphQL supports two abstract types: interfaces and unions. An `Interface` defines a list of fields; `Object` types and other Interface types which implement this Interface are guaranteed to implement those fields. Whenever a field claims it will return an Interface type, it will return a valid -implementing Object type during execution. +implementing Object type during _operation execution_. A `Union` defines a list of possible types; similar to interfaces, whenever the type system claims a union will be returned, one of the possible types will be @@ -505,7 +505,7 @@ information on the serialization of scalars in common JSON and other formats. If a GraphQL service expects a scalar type as input to an argument, coercion is observable and the rules must be well defined. If an input value does not match a coercion rule, a _request error_ must be raised (input values are validated -before execution begins). +before _operation execution_ begins). GraphQL has different constant literals to represent integer and floating-point input values, and coercion rules may apply differently depending on which type @@ -810,10 +810,10 @@ And will yield the subset of each object type queried: **Field Ordering** When querying an Object, the resulting mapping of fields are conceptually -ordered in the same order in which they were encountered during execution, -excluding fragments for which the type does not apply and fields or fragments -that are skipped via `@skip` or `@include` directives. This ordering is -correctly produced when using the {CollectFields()} algorithm. +ordered in the same order in which they were encountered during _operation +execution_, excluding fragments for which the type does not apply and fields or +fragments that are skipped via `@skip` or `@include` directives. This ordering +is correctly produced when using the {CollectFields()} algorithm. Response serialization formats capable of representing ordered maps should maintain this ordering. Serialization formats which can only represent unordered @@ -2058,8 +2058,8 @@ directive @example on Directives can also be used to annotate the type system definition language as well, which can be a useful tool for supplying additional metadata in order to -generate GraphQL execution services, produce client generated runtime code, or -many other useful extensions of the GraphQL semantics. +generate GraphQL services, produce client generated runtime code, or many other +useful extensions of the GraphQL semantics. In this example, the directive `@example` annotates field and argument definitions: @@ -2122,8 +2122,8 @@ directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT ``` The `@skip` _built-in directive_ may be provided for fields, fragment spreads, -and inline fragments, and allows for conditional exclusion during execution as -described by the `if` argument. +and inline fragments, and allows for conditional exclusion during _operation +execution_ as described by the `if` argument. In this example `experimentalField` will only be queried if the variable `$someTest` has the value `false`. @@ -2142,7 +2142,7 @@ directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT The `@include` _built-in directive_ may be provided for fields, fragment spreads, and inline fragments, and allows for conditional inclusion during -execution as described by the `if` argument. +_operation execution_ as described by the `if` argument. In this example `experimentalField` will only be queried if the variable `$someTest` has the value `true` diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index d7f8e629f..5d3307cee 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -72,7 +72,7 @@ GraphQL supports type name introspection within any _selection set_ in an operation, with the single exception of selections at the root of a subscription operation. Type name introspection is accomplished via the meta-field `__typename: String!` on any Object, Interface, or Union. It returns the name of -the concrete Object type at that point during execution. +the concrete Object type at that point during _operation execution_. This is most often used when querying against Interface or Union types to identify which actual Object type of the possible types has been returned. diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 206814d6d..5ed5c1a00 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -7,7 +7,8 @@ given GraphQL schema. An invalid request is still technically executable, and will always produce a stable result as defined by the algorithms in the Execution section, however that result may be ambiguous, surprising, or unexpected relative to a request -containing validation errors, so execution should only occur for valid requests. +containing validation errors, so _operation execution_ should only occur for +valid requests. Typically validation is performed in the context of a request immediately before execution, however a GraphQL service may execute a request without explicitly @@ -108,7 +109,7 @@ input FindDogInput { GraphQL execution will only consider the executable definitions Operation and Fragment. Type system definitions and extensions are not executable, and are not -considered during execution. +considered during _operation execution_. To avoid ambiguity, a document containing {TypeSystemDefinitionOrExtension} is invalid for execution. @@ -579,9 +580,10 @@ type that is either an Object, Interface or Union type. **Explanatory Text** If multiple field selections with the same _response name_ are encountered -during execution, the field and arguments to execute and the resulting value -should be unambiguous. Therefore any two field selections which might both be -encountered for the same object are only valid if they are equivalent. +during _operation execution_, the field and arguments to execute and the +resulting value should be unambiguous. Therefore any two field selections which +might both be encountered for the same object are only valid if they are +equivalent. During execution, the simultaneous execution of fields with the same response name is accomplished by {CollectSubfields()} before execution. diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index b2c533bb3..3fa54a450 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -47,6 +47,16 @@ document is expected to only contain a single operation. The result of the request is determined by the result of executing this operation according to the "Executing Operations” section below. +The {ExecuteRequest()} algorithm performs the preamble for _operation +execution_, completing preliminary steps before invoking the appropriate +algorithm based on the operation's type. These steps include determining the +operation to execute, coercing input values, and, for subscriptions, +establishing the source event stream. + +Note: An error raised before _operation execution_ begins will typically be a +_request error_, and once _operation execution_ begins will typically be an +_execution error_. + ExecuteRequest(schema, document, operationName, variableValues, initialValue): - Let {operation} be the result of {GetOperation(document, operationName)}. @@ -59,7 +69,10 @@ ExecuteRequest(schema, document, operationName, variableValues, initialValue): - Return {ExecuteMutation(operation, schema, coercedVariableValues, initialValue)}. - Otherwise if {operation} is a subscription operation: - - Return {Subscribe(operation, schema, coercedVariableValues, initialValue)}. + - Let {sourceStream} be the result of running + {CreateSourceEventStream(operation, schema, coercedVariableValues, + initialValue)}. + - Return {Subscribe(sourceStream, operation, schema, coercedVariableValues)}. GetOperation(document, operationName): @@ -74,27 +87,28 @@ GetOperation(document, operationName): ### Validating Requests -As explained in the Validation section, only requests which pass all validation -rules should be executed. If validation errors are known, they should be -reported in the list of "errors" in the response and the request must fail -without execution. +As explained in the Validation section, only operations from documents which +pass all validation rules should be executed. If validation errors are known, +they should be reported in the list of "errors" in the response and the request +must fail without _operation execution_. Typically validation is performed in the context of a request immediately before -execution, however a GraphQL service may execute a request without immediately -validating it if that exact same request is known to have been validated before. -A GraphQL service should only execute requests which _at some point_ were known -to be free of any validation errors, and have since not changed. +calling {ExecuteRequest()}, however a GraphQL service may execute a request +without immediately validating the document if that exact same document is known +to have been validated before. A GraphQL service should only execute operations +which _at some point_ were known to be free of any validation errors, and have +since not changed. -For example: the request may be validated during development, provided it does -not later change, or a service may validate a request once and memoize the -result to avoid validating the same request again in the future. +For example: the document may be validated during development, provided it does +not later change, or a service may validate a document once and memoize the +result to avoid validating the same document again in the future. ### Coercing Variable Values If the operation has defined any variables, then the values for those variables need to be coerced using the input coercion rules of variable's declared type. If a _request error_ is encountered during input coercion of variable values, -then the operation fails without execution. +then the request fails without _operation execution_. CoerceVariableValues(schema, operation, variableValues): @@ -138,6 +152,11 @@ provide a query root operation type. If mutations or subscriptions are supported, it must also provide a mutation or subscription root operation type, respectively. +:: The result of a GraphQL operation is produced through _operation execution_. +Operation execution begins when the execution algorithm for the operation type +is invoked: {ExecuteQuery()} for query operations, {ExecuteMutation()} for +mutation operations, and {Subscribe()} for subscription operations. + ### Query If the operation is a query, the result of the operation is the result of @@ -176,15 +195,14 @@ ExecuteMutation(mutation, schema, variableValues, initialValue): If the operation is a subscription, the result is an _event stream_ called the _response stream_ where each event in the event stream is the result of -executing the operation for each new event on an underlying _source stream_. +executing the operation’s _root selection set_ for each new event on an +underlying _source stream_ established during {ExecuteRequest()}. Executing a subscription operation creates a persistent function on the service -that maps an underlying _source stream_ to a returned _response stream_. +that maps this underlying _source stream_ to a returned _response stream_. -Subscribe(subscription, schema, variableValues, initialValue): +Subscribe(sourceStream, subscription, schema, variableValues): -- Let {sourceStream} be the result of running - {CreateSourceEventStream(subscription, schema, variableValues, initialValue)}. - Let {responseStream} be the result of running {MapSourceToResponseEvent(sourceStream, subscription, schema, variableValues)}. @@ -291,6 +309,9 @@ CreateSourceEventStream(subscription, schema, variableValues, initialValue): argumentValues)}. - Return {sourceStream}. +Note: The call to {CreateSourceEventStream()} occurs before _operation +execution_ begins, and thus an error raised here will be a _request error_. + ResolveFieldEventStream(subscriptionType, rootValue, fieldName, argumentValues): - Let {resolver} be the internal function provided by {subscriptionType} for @@ -788,9 +809,9 @@ CoerceArgumentValues(objectType, field, variableValues): Any _request error_ raised as a result of input coercion during {CoerceArgumentValues()} should be treated instead as an _execution error_. -Note: Variable values are not coerced because they are expected to be coerced -before executing the operation in {CoerceVariableValues()}, and valid operations -must only allow usage of variables of appropriate types. +Note: Variable values are not coerced because they are expected to be coerced by +{CoerceVariableValues()} before _operation execution_ begins, and valid +operations must only allow usage of variables of appropriate types. Note: Implementations are encouraged to optimize the coercion of an argument's default value by doing so only once and caching the resulting coerced value. diff --git a/spec/Section 7 -- Response.md b/spec/Section 7 -- Response.md index f79100cd2..45462291a 100644 --- a/spec/Section 7 -- Response.md +++ b/spec/Section 7 -- Response.md @@ -24,11 +24,11 @@ An _execution result_ must be map. The _execution result_ must contain an entry with key {"data"}. The value of this entry is described in the "Data" section. -If execution raised any errors, the _execution result_ must contain an entry -with key {"errors"}. The value of this entry must be a non-empty list of -_execution error_ raised during execution. Each error must be a map as described -in the "Errors" section below. If the request completed without raising any -errors, this entry must not be present. +If any errors are raised during _operation execution_, the _execution result_ +must contain an entry with key {"errors"}. The value of this entry must be a +non-empty list of _execution error_ raised during operation execution. Each +error must be a map as described in the "Errors" section below. If the request +completed without raising any errors, this entry must not be present. Note: When {"errors"} is present in a _execution result_, it may be helpful for it to appear first when serialized to make it more apparent that errors are @@ -115,19 +115,23 @@ found at `["hero", "friends"]`, the hero's first friend at ### Data -The {"data"} entry in the _execution result_ will be the result of the execution -of the requested operation. If the operation was a query, this output will be an +The {"data"} entry in the _execution result_ will be the result of the request's +_operation execution_. If the operation was a query, this output will be an object of the query root operation type; if the operation was a mutation, this output will be an object of the mutation root operation type. The response data is the result of accumulating the resolved result of all response positions during execution. -If an error was raised before execution begins, the _response_ must be a -_request error result_ which will result in no response data. +If an error was raised before _operation execution_ begins, the _response_ must +be a _request error result_ which will result in no response data. -If an error was raised during the execution that prevented a valid response, the -{"data"} entry in the response should be `null`. +If an error was raised during _operation execution_ that prevented a valid +response, the {"data"} entry in the response should be `null`. + +Note: Request errors (including those raised during {ExecuteRequest()}) occur +before _operation execution_ begins; when a request error is raised the {"data"} +entry should not be present in the result. ### Errors @@ -138,9 +142,11 @@ of data described by the error result format below. **Request Errors** :: A _request error_ is an error raised during a _request_ which results in no -response data. Typically raised before execution begins, a request error may -occur due to a parse grammar or validation error in the _Document_, an inability -to determine which operation to execute, or invalid input values for variables. +response data. Typically raised before _operation execution_ begins, a request +error may occur due to a parse grammar or validation error in the _Document_, an +inability to determine which operation to execute, invalid input values for +variables, or failure to establish a source event stream for a subscription +operation. A request error is typically the fault of the requesting client.