Skip to content

Commit c747f61

Browse files
committed
spec updates to reflect latest discussions
1 parent 19cb9c3 commit c747f61

File tree

2 files changed

+107
-48
lines changed

2 files changed

+107
-48
lines changed

spec/Section 6 -- Execution.md

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,10 @@ ExecuteQuery(query, schema, variableValues, initialValue):
144144
- If {subsequentPayloads} is empty:
145145
- Return an unordered map containing {data} and {errors}.
146146
- If {subsequentPayloads} is not empty:
147-
- Yield an unordered map containing {data}, {errors}, and an entry named
148-
{hasNext} with the value {true}.
147+
- Let {intialResponse} be an unordered map containing {data}, {errors}, and an
148+
entry named {hasNext} with the value {true}.
149149
- Let {iterator} be the result of running
150-
{YieldSubsequentPayloads(subsequentPayloads)}.
150+
{YieldSubsequentPayloads(intialResponse, subsequentPayloads)}.
151151
- For each {payload} yielded by {iterator}:
152152
- If a termination signal is received:
153153
- Send a termination signal to {iterator}.
@@ -178,10 +178,10 @@ ExecuteMutation(mutation, schema, variableValues, initialValue):
178178
- If {subsequentPayloads} is empty:
179179
- Return an unordered map containing {data} and {errors}.
180180
- If {subsequentPayloads} is not empty:
181-
- Yield an unordered map containing {data}, {errors}, and an entry named
182-
{hasNext} with the value {true}.
181+
- Let {intialResponse} be an unordered map containing {data}, {errors}, and an
182+
entry named {hasNext} with the value {true}.
183183
- Let {iterator} be the result of running
184-
{YieldSubsequentPayloads(subsequentPayloads)}.
184+
{YieldSubsequentPayloads(intialResponse, subsequentPayloads)}.
185185
- For each {payload} yielded by {iterator}:
186186
- If a termination signal is received:
187187
- Send a termination signal to {iterator}.
@@ -341,10 +341,10 @@ ExecuteSubscriptionEvent(subscription, schema, variableValues, initialValue):
341341
- If {subsequentPayloads} is empty:
342342
- Return an unordered map containing {data} and {errors}.
343343
- If {subsequentPayloads} is not empty:
344-
- Yield an unordered map containing {data}, {errors}, and an entry named
345-
{hasNext} with the value {true}.
344+
- Let {intialResponse} be an unordered map containing {data}, {errors}, and an
345+
entry named {hasNext} with the value {true}.
346346
- Let {iterator} be the result of running
347-
{YieldSubsequentPayloads(subsequentPayloads)}.
347+
{YieldSubsequentPayloads(intialResponse, subsequentPayloads)}.
348348
- For each {payload} yielded by {iterator}:
349349
- If a termination signal is received:
350350
- Send a termination signal to {iterator}.
@@ -372,29 +372,42 @@ If an operation contains subsequent payload records resulting from `@stream` or
372372
`@defer` directives, the {YieldSubsequentPayloads} algorithm defines how the
373373
payloads should be processed.
374374

375-
YieldSubsequentPayloads(subsequentPayloads):
375+
YieldSubsequentPayloads(intialResponse, subsequentPayloads):
376376

377+
- Let {initialRecords} be any items in {subsequentPayloads} with a completed
378+
{dataExecution}.
379+
- Initialize {initialIncremental} to an empty list.
380+
- For each {record} in {initialRecords}:
381+
- Remove {record} from {subsequentPayloads}.
382+
- If {isCompletedIterator} on {record} is {true}:
383+
- Continue to the next record in {records}.
384+
- Let {payload} be the completed result returned by {dataExecution}.
385+
- Append {payload} to {initialIncremental}.
386+
- If {initialIncremental} is not empty:
387+
- Add an entry to {intialResponse} named `incremental` containing the value
388+
{incremental}.
389+
- Yield {intialResponse}.
377390
- While {subsequentPayloads} is not empty:
378391
- If a termination signal is received:
379392
- For each {record} in {subsequentPayloads}:
380393
- If {record} contains {iterator}:
381394
- Send a termination signal to {iterator}.
382395
- Return.
383-
- Let {record} be the first item in {subsequentPayloads} with a completed
396+
- Wait for at least one record in {subsequentPayloads} to have a completed
384397
{dataExecution}.
385-
- Remove {record} from {subsequentPayloads}.
386-
- If {isCompletedIterator} on {record} is {true}:
387-
- If {subsequentPayloads} is empty:
388-
- Yield a map containing a field `hasNext` with the value {false}.
389-
- Return.
390-
- If {subsequentPayloads} is not empty:
391-
- Continue to the next record in {subsequentPayloads}.
392-
- Let {payload} be the completed result returned by {dataExecution}.
393-
- If {record} is not the final element in {subsequentPayloads}:
394-
- Add an entry to {payload} named `hasNext` with the value {true}.
395-
- If {record} is the final element in {subsequentPayloads}:
396-
- Add an entry to {payload} named `hasNext` with the value {false}.
397-
- Yield {payload}
398+
- Let {subsequentResponse} be an unordered map with an entry {incremental}
399+
initialized to an empty list.
400+
- Let {records} be the items in {subsequentPayloads} with a completed
401+
{dataExecution}.
402+
- For each {record} in {records}:
403+
- Remove {record} from {subsequentPayloads}.
404+
- If {isCompletedIterator} on {record} is {true}:
405+
- Continue to the next record in {records}.
406+
- Let {payload} be the completed result returned by {dataExecution}.
407+
- Append {payload} to {incremental}.
408+
- If {subsequentPayloads} is empty:
409+
- Add an entry to {response} named `hasNext` with the value {false}.
410+
- Yield {response}
398411

399412
## Executing Selection Sets
400413

@@ -900,7 +913,8 @@ variableValues, subsequentPayloads):
900913
- Wait for the result of {dataExecution} on {parentRecord}.
901914
- If {errors} is not empty:
902915
- Add an entry to {payload} named `errors` with the value {errors}.
903-
- Add an entry to {payload} named `data` with the value {data}.
916+
- Add an entry to {payload} named `items` with a list containing the value
917+
{data}.
904918
- Add an entry to {payload} named `label` with the value {label}.
905919
- Add an entry to {payload} named `path` with the value {itemPath}.
906920
- Return {payload}.

spec/Section 7 -- Response.md

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@ request failed before execution, due to a syntax error, missing information, or
2323
validation error, this entry must not be present.
2424

2525
When the response of the GraphQL operation is an event stream, the first value
26-
will be the initial response. All subsequent values may contain `label` and
27-
`path` entries. These two entries are used by clients to identify the `@defer`
28-
or `@stream` directive from the GraphQL operation that triggered this value to
29-
be returned by the event stream. When a label is provided, the combination of
30-
these two entries will be unique across all values returned by the event stream.
26+
will be the initial response. All subsequent values may contain an `incremental`
27+
entry, containing a list of Defer or Stream responses.
28+
29+
The `label` and `path` entries on Defer and Stream responses are used by clients
30+
to identify the `@defer` or `@stream` directive from the GraphQL operation that
31+
triggered this response to be included in an `incremental` entry on a value
32+
returned by the event stream. When a label is provided, the combination of these
33+
two entries will be unique across all values returned by the event stream.
3134

3235
If the response of the GraphQL operation is an event stream, each response map
3336
must contain an entry with key `hasNext`. The value of this entry is `true` for
@@ -45,11 +48,13 @@ set, must have a map as its value. This entry is reserved for implementors to
4548
extend the protocol however they see fit, and hence there are no additional
4649
restrictions on its contents. When the response of the GraphQL operation is an
4750
event stream, implementors may send subsequent payloads containing only
48-
`hasNext` and `extensions` entries.
51+
`hasNext` and `extensions` entries. Defer and Stream responses may also contain
52+
an entry with the key `extensions`, also reserved for implementors to extend the
53+
protocol however they see fit.
4954

5055
To ensure future changes to the protocol do not break existing services and
5156
clients, the top level response map must not contain any entries other than the
52-
three described above.
57+
five described above.
5358

5459
Note: When `errors` is present in the response, it may be helpful for it to
5560
appear first when serialized to make it more clear when errors are present in a
@@ -62,11 +67,6 @@ requested operation. If the operation was a query, this output will be an object
6267
of the query root operation type; if the operation was a mutation, this output
6368
will be an object of the mutation root operation type.
6469

65-
If the result of the operation is an event stream, the `data` entry in
66-
subsequent values will be of the type of a particular field in the GraphQL
67-
result. The adjacent `path` field will contain the path segments of the field
68-
this data is associated with.
69-
7070
If an error was raised before execution begins, the `data` entry should not be
7171
present in the result.
7272

@@ -263,7 +263,43 @@ discouraged.
263263
}
264264
```
265265

266-
## Path
266+
### Incremental
267+
268+
The `incremental` entry in the response is a non-empty list of Defer or Stream
269+
responses. If the response of the GraphQL operation is an event stream, this
270+
field may appear on both the initial and subsequent values.
271+
272+
#### Stream response
273+
274+
A stream response is a map that may appear as an item in the `incremental` entry
275+
of a response. A stream response is the result of an associated `@stream`
276+
directive in the operation. A stream response must contain `items` and `path`
277+
entries and may contain `label`, `errors`, and `extensions` entries.
278+
279+
##### Items
280+
281+
The `items` entry in a stream response is a list of results from the execution
282+
of the associated @stream directive. This output will be a list of the same type
283+
of the field with the associated `@stream` directive. If `items` is set to
284+
`null`, it indicates that an error has caused a `null` to bubble up to a field
285+
higher than the list field with the associated `@stream` directive.
286+
287+
#### Defer response
288+
289+
A defer response is a map that may appear as an item in the `incremental` entry
290+
of a response. A defer response is the result of an associated `@defer`
291+
directive in the operation. A defer response must contain `data` and `path`
292+
entries and may contain `label`, `errors`, and `extensions` entries.
293+
294+
##### Data
295+
296+
The `data` entry in a Defer response will be of the type of a particular field
297+
in the GraphQL result. The adjacent `path` field will contain the path segments
298+
of the field this data is associated with. If `data` is set to `null`, it
299+
indicates that an error has caused a `null` to bubble up to a field higher than
300+
the field that contains the fragment with the associated `@defer` directive.
301+
302+
#### Path
267303

268304
A `path` field allows for the association to a particular field in a GraphQL
269305
result. This field should be a list of path segments starting at the root of the
@@ -273,21 +309,30 @@ indices should be 0-indexed integers. If the path is associated to an aliased
273309
field, the path should use the aliased name, since it represents a path in the
274310
response, not in the request.
275311

276-
When the `path` field is present on a GraphQL response, it indicates that the
277-
`data` field is not the root query or mutation result, but is rather associated
278-
to a particular field in the root result.
312+
When the `path` field is present on a Stream response, it indicates that the
313+
`items` field represents the partial result of the list field containing the
314+
corresponding `@stream` directive. All but the non-final path segments must
315+
refer to the location of the list field containing the corresponding `@stream`
316+
directive. The final segment of the path list must be a 0-indexed integer. This
317+
integer indicates that this result is set at a range, where the beginning of the
318+
range is at the index of this integer, and the length of the range is the length
319+
of the data.
320+
321+
When the `path` field is present on a Defer response, it indicates that the
322+
`data` field represents the result of the fragment containing the corresponding
323+
`@defer` directive. The path segments must point to the location of the result
324+
of the field containing the associated `@defer` directive.
279325

280326
When the `path` field is present on an "Error result", it indicates the response
281327
field which experienced the error.
282328

283-
## Label
329+
#### Label
284330

285-
If the response of the GraphQL operation is an event stream, subsequent values
286-
may contain a string field `label`. This `label` is the same label passed to the
287-
`@defer` or `@stream` directive that triggered this value. This allows clients
288-
to identify which `@defer` or `@stream` directive is associated with this value.
289-
`label` will not be present if the corresponding `@defer` or `@stream` directive
290-
is not passed a `label` argument.
331+
Stream and Defer responses may contain a string field `label`. This `label` is
332+
the same label passed to the `@defer` or `@stream` directive associated with the
333+
response. This allows clients to identify which `@defer` or `@stream` directive
334+
is associated with this value. `label` will not be present if the corresponding
335+
`@defer` or `@stream` directive is not passed a `label` argument.
291336

292337
## Serialization Format
293338

0 commit comments

Comments
 (0)