Skip to content

Define 'execution' as in 'before execution begins' #894

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

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d7eaf72
Clarify 'before execution begins' in response
benjie Oct 18, 2021
b76671b
Extract common logic from ExecuteQuery, ExecuteMutation and ExecuteSu…
benjie Apr 28, 2023
c9837a4
Change ExecuteSelectionSet to ExecuteGroupedFieldSet
benjie Apr 28, 2023
a52310e
Correct reference to MergeSelectionSets
benjie Aug 21, 2023
60a9c35
move Field Collection section earlier (#1111)
yaacovCR Oct 17, 2024
a1de2dd
Merge branch 'main' into benjie/incremental-common
benjie Jan 9, 2025
e8f80c8
Merge branch 'main' into benjie/incremental-common
benjie Mar 6, 2025
213fd2a
Define 'grouped field set'
benjie Mar 6, 2025
383cf8e
that -> which
benjie Mar 6, 2025
48a789b
More similar to prior wording
benjie Mar 6, 2025
0b9eed7
Remove reason from definition
benjie Mar 6, 2025
0728c4a
subGroupedFieldSet -> fieldGroupedFieldSet
benjie Mar 6, 2025
140c3da
Add note for clarity
benjie Mar 6, 2025
0e175cb
Merge branch 'main' into before-execution-begins-note
benjie Mar 7, 2025
5c2ad6a
Distinguish between Processing and Execution
martinbonnin Mar 27, 2025
6a7271b
Merge branch 'main' into before-execution-begins-note
benjie Apr 3, 2025
6150bec
Define 'execution'
benjie Apr 3, 2025
d60481a
Correction
benjie Apr 3, 2025
aa55df7
Update spec/Section 6 -- Execution.md
martinbonnin Apr 3, 2025
94ad176
Update spec/Section 6 -- Execution.md
martinbonnin Apr 3, 2025
15a6c11
format
martinbonnin Apr 3, 2025
41450b7
keep execute here
martinbonnin Apr 17, 2025
65df539
Merge branch 'main' into benjie/incremental-common
benjie Apr 17, 2025
d68df95
move field collections into one section, section reworking, minor wor…
leebyron Apr 17, 2025
180a51c
Apply suggestions from code review
benjie Apr 24, 2025
3c6dfb3
Rename 'ExecuteGroupedFieldSet' to 'ExecuteCollectedFields'
benjie Apr 25, 2025
5459f16
Merge branch 'main' into benjie/incremental-common
benjie May 1, 2025
7a740be
Merge branch 'benjie/incremental-common' into before-execution-begins…
benjie May 1, 2025
2fcc58b
Merge remote-tracking branch 'martinbonnin/clarify-execution' into be…
benjie May 1, 2025
11f33ba
Editorial and eliding
benjie May 1, 2025
1f11a6b
Add clarity
benjie May 1, 2025
ec28769
Grammar
benjie May 1, 2025
b428f39
Reorder text
benjie May 1, 2025
7ed055a
Fix typo and remove note
benjie May 1, 2025
1be44d0
Define 'execution' as in 'before execution begins'
leebyron Jul 2, 2025
7bafeaf
Merge branch 'lee/before-execution-begins-note' into before-execution…
benjie Jul 2, 2025
f16f52f
Revert to previous terminology and algorithm names.
benjie Jul 2, 2025
94241a7
Rename 'execution' to 'operation execution'
benjie Jul 2, 2025
bc5618c
Slight tweaks for subscriptions
benjie Jul 3, 2025
8606033
Clarity
benjie Jul 3, 2025
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
22 changes: 11 additions & 11 deletions spec/Section 3 -- Type System.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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`.
Expand All @@ -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`
Expand Down
2 changes: 1 addition & 1 deletion spec/Section 4 -- Introspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 7 additions & 5 deletions spec/Section 5 -- Validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
63 changes: 42 additions & 21 deletions spec/Section 6 -- Execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)}.
Expand All @@ -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):

Expand All @@ -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):

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)}.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
34 changes: 20 additions & 14 deletions spec/Section 7 -- Response.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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.

Expand Down