From 13c74dce824bcb2703328faf346f1db3f723c0f2 Mon Sep 17 00:00:00 2001 From: Rob Richard Date: Tue, 23 Jun 2020 11:43:26 -0400 Subject: [PATCH 1/8] change initial_count to initialCount --- spec/Section 3 -- Type System.md | 4 ++-- spec/Section 6 -- Execution.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 29990a9c2..f15bcb253 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -1950,7 +1950,7 @@ fragment someFragment on User { ### @stream ```graphql -directive @stream(label: String!, initial_count: Int!, if: Boolean) on FIELD +directive @stream(label: String!, initialCount: Int!, if: Boolean) on FIELD ``` The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such asynchronous iterators to provide a partial @@ -1960,7 +1960,7 @@ list in the initial response, and additional list items in subsequent responses. query myQuery($shouldDefer: Boolean) { user { friends(first: 10) { - nodes @stream(label: "friendsStream", initial_count: 5) + nodes @stream(label: "friendsStream", initialCount: 5) } } } diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index 4ea1f0282..ebb741f06 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -607,7 +607,7 @@ ExecuteField(objectType, objectValue, fieldType, fields, variableValues, subsequ * Let {fieldName} be the field name of {field}. * Let {argumentValues} be the result of {CoerceArgumentValues(objectType, field, variableValues)} * If {field} provides the directive `@stream`, let {streamDirective} be that directive. - * Let {initialCount} be the value or variable provided to {streamDirective}'s {initial_count} argument. + * Let {initialCount} be the value or variable provided to {streamDirective}'s {initialCount} argument. * Let {resolvedValue} be {ResolvedFieldGenerator(objectType, objectValue, fieldName, argumentValues, initialCount)}. * Let {result} be the result of calling {CompleteValue(fieldType, fields, resolvedValue, variableValues, subsequentPayloads, parentPath)}. * Append {fieldName} to the {path} field of every {subsequentPayloads}. @@ -721,7 +721,7 @@ to the expected return type. If the return type is another Object type, then the field execution process continues recursively. In the case where a value returned for a list type field is an iterator due to `@stream` specified on the field, value completition iterates over the iterator until the number of items -yield by the iterator satisfies `initial_count` specified on the `@stream` directive. +yield by the iterator satisfies `initialCount` specified on the `@stream` directive. Unresolved items in the iterator will be stored in a stream record which the executor resumes to execute after the initial execution finishes. @@ -769,7 +769,7 @@ CompleteValue(fieldType, fields, result, variableValues, subsequentPayloads, par * Let {field} be thte first entry in {fields}. * Let {innerType} be the inner type of {fieldType}. * Let {streamDirective} be the `@stream` directived provided on {field}. - * Let {initialCount} be the value or variable provided to {streamDirective}'s {initial_count} argument. + * Let {initialCount} be the value or variable provided to {streamDirective}'s {initialCount} argument. * Let {label} be the value or variable provided to {streamDirective}'s {label} argument. * Let {resolvedItems} be an empty list * For each {members} in {result}: From 373d66ab4610b94da77b968c792a897ef13d2540 Mon Sep 17 00:00:00 2001 From: Rob Richard Date: Wed, 24 Jun 2020 09:43:27 -0400 Subject: [PATCH 2/8] isFinal > hasNext rfc --- rfcs/DeferStream.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rfcs/DeferStream.md b/rfcs/DeferStream.md index ae1b364f6..b05456d2b 100644 --- a/rfcs/DeferStream.md +++ b/rfcs/DeferStream.md @@ -68,7 +68,7 @@ Each subsequent payload will be an object with the following properties * `label`: The string that was passed to the label argument of the `@defer` or `@stream` directive that corresponds to this results. * `data`: The data that is being delivered incrementally. * `path`: a list of keys (with plural indexes) from the root of the response to the insertion point that informs the client how to patch a subsequent delta payload into the original payload. -* `isFinal`: A boolean that is present and `false` when there are more payloads that will be sent for this operation. +* `hasNext`: A boolean that is present and `true` when there are more payloads that will be sent for this operation. The last payload in a multi payload response should return `hasNext: false`. `hasNext` is not required for single-payload responses to preserve backwards compatibility. * `errors`: An array that will be present and contain any field errors that are produced while executing the deferred or streamed selection set. * `extensions`: For implementors to extend the protocol @@ -104,7 +104,7 @@ fragment GroupAdminFragment { // payload 1 { data: {id: 1}, - isFinal: false + hasNext: true } // payload 2 @@ -112,7 +112,7 @@ fragment GroupAdminFragment { label: "friendStream" path: [“viewer”, “friends”, 1], data: {id: 4}, - isFinal: false + hasNext: true } // payload 3 @@ -120,7 +120,7 @@ fragment GroupAdminFragment { label: "friendStream" path: [“viewer”, “friends”, 2], data: {id: 5}, - isFinal: false + hasNext: true } // payload 4 @@ -128,6 +128,7 @@ fragment GroupAdminFragment { label: "groupAdminDefer", path: [“viewer”], data: {managed_groups: [{id: 1, id: 2}]} + hasNext: false } ``` From a07730963918c991e8b6d217114e477da81ef73a Mon Sep 17 00:00:00 2001 From: Rob Richard Date: Thu, 25 Jun 2020 14:41:26 -0400 Subject: [PATCH 3/8] add payload fields to Response section --- spec/Section 3 -- Type System.md | 7 +++- spec/Section 6 -- Execution.md | 6 +++- spec/Section 7 -- Response.md | 55 ++++++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index f15bcb253..1ecba9a24 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -1753,7 +1753,12 @@ A GraphQL schema describes directives which are used to annotate various parts of a GraphQL document as an indicator that they should be evaluated differently by a validator, executor, or client tool such as a code generator. -GraphQL implementations should provide the `@skip`, `@include`, `@defer` and `@stream` directives. +GraphQL implementations should provide the `@skip` and `@include` directives. + +GraphQL implementations are not required to implement the `@defer` and `@stream` +directives. If they are implemented, they must be implemented according to the +specification. GraphQL implementations that do not support these directives must +not make them available via introspection. GraphQL implementations that support the type system definition language must provide the `@deprecated` directive if representing deprecated portions of diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index ebb741f06..099120fcd 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -141,6 +141,10 @@ ExecuteQuery(query, schema, variableValues, initialValue): * For each {payload} in {subsequentPayloads}: * If {payload} is a Deferred Fragment Record: * Yield the value from calling {ResolveDeferredFragmentRecord(payload, variableValues, subsequentPayloads)}. + * If {payload} is not the final payload in {subsequentPayloads} + * Add an entry to {payload} named `hasNext` with the value {true}. + * If {payload} is the final payload in {subsequentPayloads} + * Add an entry to {payload} named `hasNext` with the value {false}. * If {payload} is a Stream Record: * Yield ResolveStreamRecord(payload, variableValues, subsequentPayloads). @@ -712,7 +716,7 @@ Note: It is common for {resolver} to be asynchronous due to relying on reading an underlying database or networked service to produce a value. This necessitates the rest of a GraphQL executor to handle an asynchronous execution flow. In addition, a commom implementation of {generator} is to leverage -asynchronos iterators or asynchronos generators provided by many programing languages. +asynchronous iterators or asynchronous generators provided by many programing languages. ### Value Completion diff --git a/spec/Section 7 -- Response.md b/spec/Section 7 -- Response.md index f51fb5982..0ce53e63a 100644 --- a/spec/Section 7 -- Response.md +++ b/spec/Section 7 -- Response.md @@ -8,11 +8,11 @@ request. A response may contain both a partial response as well as encountered errors in the case that a field error occurred on a field which was replaced with {null}. +A response to a GraphQL operation must be a map or an event stream of maps. The +value of this map is described in the "Response Format" section. ## Response Format -A response to a GraphQL operation must be a map. - If the operation encountered any errors, the response map must contain an entry with key `errors`. The value of this entry is described in the "Errors" section. If the operation completed without encountering any errors, this entry @@ -23,11 +23,24 @@ with key `data`. The value of this entry is described in the "Data" section. If the operation failed before execution, due to a syntax error, missing information, or validation error, this entry must not be present. +If the response of the GraphQL operation is an event stream, each response map +must contain an entry with key `hasNext`. The value of this entry is `true` for +all but the last response in the stream. The value of this entry is `false` for +the last response of the stream. This entry is not required for GraphQL +operations that return a single response map. + The response map may also contain an entry with key `extensions`. This entry, if set, must have a map as its value. This entry is reserved for implementors to extend the protocol however they see fit, and hence there are no additional restrictions on its contents. +When the response of the GraphQL operation is an event stream, the first value +will be the initial response. All subsequent values must contain `label` and +`path` entries. These two entries are used by clients to identify the the +`@defer` or `@stream` directive from the GraphQL operation that triggered this +value to be returned by the event stream. The combination of these two entries +must be unique across all values returned by the event stream. + To ensure future changes to the protocol do not break existing servers and clients, the top level response map must not contain any entries other than the three described above. @@ -43,6 +56,11 @@ requested operation. If the operation was a query, this output will be an object of the schema's query root type; if the operation was a mutation, this output will be an object of the schema's mutation root type. +If the result of the operation is an event stream, the `data` entry in +subsequent values will be an object of the type of a particular field in the +GraphQL result. The adjacent `path` field will contain the path segments of +the field this data is associated with. + If an error was encountered before execution begins, the `data` entry should not be present in the result. @@ -82,14 +100,8 @@ associated syntax element. If an error can be associated to a particular field in the GraphQL result, it must contain an entry with the key `path` that details the path of the response field which experienced the error. This allows clients to identify -whether a `null` result is intentional or caused by a runtime error. - -This field should be a list of path segments starting at the root of the -response and ending with the field associated with the error. Path segments -that represent fields should be strings, and path segments that -represent list indices should be 0-indexed integers. If the error happens -in an aliased field, the path to the error should use the aliased name, since -it represents a path in the response, not in the query. +whether a `null` result is intentional or caused by a runtime error. The value +of this field is described in the "Path" section. For example, if fetching one of the friends' names fails in the following query: @@ -220,6 +232,29 @@ still discouraged. ``` +## Path + +A `path` field allows for the association to a particular field in a GraphQL +result. This field should be a list of path segments starting at the root of the +response and ending with the field to be associated with. Path segments +that represent fields should be strings, and path segments that +represent list indices should be 0-indexed integers. If the path is associated to +an aliased field, the path should use the aliased name, since it represents a path in the response, not in the query. + +When the `path` field is present on a GraphQL response, it indicates that the +`data` field is not the root query or mutation result, but is rather associated to +a particular field in the root result. + +When the `path` field is present on an "Error result", it indicates the response field which experienced the error. + +## Label + +If the response of the GraphQL operation is an event stream, subsequent values +will contain a string field `label`. This `label` is the same label passed to +the `@defer` or `@stream` directive that triggered this value. This allows +clients to identify which `@defer` or `@stream` directive is associated with +this value. + ## Serialization Format GraphQL does not require a specific serialization format. However, clients From 125fb6c6da0df2a02cfe3257d49c38b1028cce23 Mon Sep 17 00:00:00 2001 From: Rob Richard Date: Thu, 25 Jun 2020 18:15:11 -0400 Subject: [PATCH 4/8] add stream validation for overlapping fields --- spec/Section 5 -- Validation.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 317e88de6..73e6e23fb 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -411,6 +411,7 @@ FieldsInSetCanMerge(set): {set} including visiting fragments and inline fragments. * Given each pair of members {fieldA} and {fieldB} in {fieldsForName}: * {SameResponseShape(fieldA, fieldB)} must be true. + * {SameStreamDirective(fieldA, fieldB)} must be true. * If the parent types of {fieldA} and {fieldB} are equal or if either is not an Object Type: * {fieldA} and {fieldB} must have identical field names. @@ -444,6 +445,16 @@ SameResponseShape(fieldA, fieldB): * If {SameResponseShape(subfieldA, subfieldB)} is false, return false. * Return true. +SameStreamDirective(fieldA, fieldB): + + * If neither {fieldA} nor {fieldB} has a directive named `stream`. + * Return true. + * If both {fieldA} and {fieldB} have a directive named `stream`. + * Let {streamA} be the directive named `stream` on {fieldA}. + * Let {streamB} be the directive named `stream` on {fieldB}. + * If {streamA} and {streamB} have identical sets of arguments, return true. + * Return false. + **Explanatory Text** If multiple field selections with the same response names are encountered From 94de88ddc664a55a7d344cea440eeab3b6df70f9 Mon Sep 17 00:00:00 2001 From: Rob Richard Date: Mon, 29 Jun 2020 15:59:17 -0400 Subject: [PATCH 5/8] spelling updates --- spec/Section 3 -- Type System.md | 6 +++--- spec/Section 6 -- Execution.md | 30 +++++++++++++++--------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 1ecba9a24..eb1634f3f 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -1935,8 +1935,8 @@ The `@defer` directive may be provided for fragment spreads and inline fragments inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is -delivered in the initial response and data deferred delivered in a subsequent response. -`@include` and `@skip` take presedence over `@defer`. +delivered in the initial response and data deferred is delivered in a subsequent +response. `@include` and `@skip` take presedence over `@defer`. ```graphql example query myQuery($shouldDefer: Boolean) { @@ -1958,7 +1958,7 @@ fragment someFragment on User { directive @stream(label: String!, initialCount: Int!, if: Boolean) on FIELD ``` The `@stream` directive may be provided for a field of `List` type so that the -backend can leverage technology such asynchronous iterators to provide a partial +backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take presedence over `@stream`. ```graphql example diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index 099120fcd..3ad6b601d 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -26,7 +26,7 @@ request is determined by the result of executing this operation according to the "Executing Operations” section below. ExecuteRequest(schema, document, operationName, variableValues, initialValue): - Note: the execution assumes implementing language support coroutines. + Note: the execution assumes implementing language supports coroutines. Alternatively, the socket can provide a write buffer pointer to allow {ExecuteRequest()} to directly write payloads into the buffer. * Let {operation} be the result of {GetOperation(document, operationName)}. @@ -337,7 +337,7 @@ response map. ExecuteSelectionSet(selectionSet, objectType, objectValue, variableValues, subsequentPayloads, parentPath): * If {subsequentPayloads} is not provided, initialize it to the empty set. - * If {parentPath} is not provided, initialize it to an emtpy list. + * If {parentPath} is not provided, initialize it to an empty list. * Let {groupedFieldSet} be the result of {CollectFields(objectType, objectValue, selectionSet, variableValues, subsequentPayloads, parentPath)}. * Initialize {resultMap} to an empty ordered map. @@ -468,11 +468,11 @@ Before execution, the selection set is converted to a grouped field set by calling {CollectFields()}. Each entry in the grouped field set is a list of fields that share a response key (the alias if defined, otherwise the field name). This ensures all fields with the same response key included via -referenced fragments are executed at the same time. A deferred seclection set's -fields will not be included in the grouped field set. Rather, a record -representing the deferred fragment and addition context will be stored in a -list. The executor revisits and resume execution for the list of deferred -fragment records after the initial execution finishes. +referenced fragments are executed at the same time. A deferred selection +set's fields will not be included in the grouped field set. Rather, a record +representing the deferred fragment and additional context will be stored in a +list. The executor revisits and resumes execution for the list of deferred +fragment records after the initial execution is initiated. As an example, collecting the fields of this selection set would collect two @@ -686,8 +686,8 @@ This is exposed via {ResolveFieldValue}, which produces a value for a given field on a type for a real value. In addition, {ResolveFieldGenerator} will be exposed to produce an iterator for a field with `List` return type. The internal system may optionally define a generator function. In the case -where the generator is not defined, the GraphQL executor provide a default generator. -For example, a trivial generator that yield the entire list upon the first iteration. +where the generator is not defined, the GraphQL executor provides a default generator. +For example, a trivial generator that yields the entire list upon the first iteration. As an example, a {ResolveFieldValue} might accept the {objectType} `Person`, the {field} {"soulMate"}, and the {objectValue} representing John Lennon. It would be @@ -695,7 +695,7 @@ expected to yield the value representing Yoko Ono. A {ResolveFieldGenerator} might accept the {objectType} `MusicBand`, the {field} {"members"}, and the {objectValue} representing Beatles. It would be expected to yield -a iterator of values representing, John Lennon, Paul, McCartney, Ringo Starr and +a iterator of values representing, John Lennon, Paul McCartney, Ringo Starr and George Harrison. ResolveFieldValue(objectType, objectValue, fieldName, argumentValues): @@ -705,7 +705,7 @@ ResolveFieldValue(objectType, objectValue, fieldName, argumentValues): ResolveFieldGenerator(objectType, objectValue, fieldName, argumentValues, initialCount): * If {objectType} provide an internal function {generatorResolver} for - generating partitially resolved valueof a list field named {fieldName}: + generating partitially resolved value of a list field named {fieldName}: * Let {generatorResolver} be the internal function. * Return the iterator from calling {generatorResolver}, providing {objectValue}, {argumentValues} and {initialCount}. @@ -716,7 +716,7 @@ Note: It is common for {resolver} to be asynchronous due to relying on reading an underlying database or networked service to produce a value. This necessitates the rest of a GraphQL executor to handle an asynchronous execution flow. In addition, a commom implementation of {generator} is to leverage -asynchronous iterators or asynchronous generators provided by many programing languages. +asynchronous iterators or asynchronous generators provided by many programming languages. ### Value Completion @@ -769,8 +769,8 @@ CompleteValue(fieldType, fields, result, variableValues, subsequentPayloads, par * If {result} is {null} (or another internal value similar to {null} such as {undefined} or {NaN}), return {null}. * If {fieldType} is a List type: - * If {result} is a iterator: - * Let {field} be thte first entry in {fields}. + * If {result} is an iterator: + * Let {field} be the first entry in {fields}. * Let {innerType} be the inner type of {fieldType}. * Let {streamDirective} be the `@stream` directived provided on {field}. * Let {initialCount} be the value or variable provided to {streamDirective}'s {initialCount} argument. @@ -784,7 +784,7 @@ CompleteValue(fieldType, fields, result, variableValues, subsequentPayloads, par * Let {streamRecord} be the result of calling {CreateStreamRecord(label, initialCount, result, remainingItems, initialCount, fields, innerType, parentPath)} * Append {streamRecord} to {subsequentPayloads}. * Let {result} be {initialItems}. - * Exit For each loop. + * Exit for each loop. * If {result} is not a collection of values, throw a field error. * Let {innerType} be the inner type of {fieldType}. * Return a list where each list item is the result of calling From f922219a6e45e1a9b3d6d053f80446a4f87b8307 Mon Sep 17 00:00:00 2001 From: Rob Richard Date: Mon, 29 Jun 2020 16:03:00 -0400 Subject: [PATCH 6/8] add note about re-execution --- spec/Section 6 -- Execution.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index 3ad6b601d..4a6a98fb4 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -472,7 +472,9 @@ referenced fragments are executed at the same time. A deferred selection set's fields will not be included in the grouped field set. Rather, a record representing the deferred fragment and additional context will be stored in a list. The executor revisits and resumes execution for the list of deferred -fragment records after the initial execution is initiated. +fragment records after the initial execution is initiated. This deferred +execution would ‘re-execute’ fields with the same response key that were +present in the grouped field set. As an example, collecting the fields of this selection set would collect two From 528509e057272fa410ca67cac272a177b5049434 Mon Sep 17 00:00:00 2001 From: Rob Richard Date: Wed, 1 Jul 2020 09:33:58 -0400 Subject: [PATCH 7/8] add note about final payloads --- spec/Section 7 -- Response.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/spec/Section 7 -- Response.md b/spec/Section 7 -- Response.md index 0ce53e63a..fe22a07ed 100644 --- a/spec/Section 7 -- Response.md +++ b/spec/Section 7 -- Response.md @@ -23,24 +23,29 @@ with key `data`. The value of this entry is described in the "Data" section. If the operation failed before execution, due to a syntax error, missing information, or validation error, this entry must not be present. +When the response of the GraphQL operation is an event stream, the first value +will be the initial response. All subsequent values may contain `label` and +`path` entries. These two entries are used by clients to identify the the +`@defer` or `@stream` directive from the GraphQL operation that triggered this +value to be returned by the event stream. The combination of these two entries +must be unique across all values returned by the event stream. + If the response of the GraphQL operation is an event stream, each response map must contain an entry with key `hasNext`. The value of this entry is `true` for all but the last response in the stream. The value of this entry is `false` for the last response of the stream. This entry is not required for GraphQL -operations that return a single response map. +operations that return a single response map. + +The GraphQL server may determine there are no more values in the event stream +after a previous value with `hasNext`: `true` has been emitted. In this case +the last value in the event stream should be a map without `data`, `label`, +and `path` entries, and a `hasNext` entry with a value of `false`. The response map may also contain an entry with key `extensions`. This entry, if set, must have a map as its value. This entry is reserved for implementors to extend the protocol however they see fit, and hence there are no additional restrictions on its contents. -When the response of the GraphQL operation is an event stream, the first value -will be the initial response. All subsequent values must contain `label` and -`path` entries. These two entries are used by clients to identify the the -`@defer` or `@stream` directive from the GraphQL operation that triggered this -value to be returned by the event stream. The combination of these two entries -must be unique across all values returned by the event stream. - To ensure future changes to the protocol do not break existing servers and clients, the top level response map must not contain any entries other than the three described above. @@ -250,7 +255,7 @@ When the `path` field is present on an "Error result", it indicates the response ## Label If the response of the GraphQL operation is an event stream, subsequent values -will contain a string field `label`. This `label` is the same label passed to +may contain a string field `label`. This `label` is the same label passed to the `@defer` or `@stream` directive that triggered this value. This allows clients to identify which `@defer` or `@stream` directive is associated with this value. From 180681269be41ec6e0cccc7aba2f5c184b90d00a Mon Sep 17 00:00:00 2001 From: Rob Richard Date: Wed, 1 Jul 2020 20:31:50 -0400 Subject: [PATCH 8/8] label is optional --- spec/Section 3 -- Type System.md | 4 ++-- spec/Section 7 -- Response.md | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index eb1634f3f..d8c2c38fe 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -1929,7 +1929,7 @@ type ExampleType { ### @defer ```graphql -directive @defer(label: String!, if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT +directive @defer(label: String, if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT ``` The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate @@ -1955,7 +1955,7 @@ fragment someFragment on User { ### @stream ```graphql -directive @stream(label: String!, initialCount: Int!, if: Boolean) on FIELD +directive @stream(label: String, initialCount: Int!, if: Boolean) on FIELD ``` The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial diff --git a/spec/Section 7 -- Response.md b/spec/Section 7 -- Response.md index fe22a07ed..f2790a583 100644 --- a/spec/Section 7 -- Response.md +++ b/spec/Section 7 -- Response.md @@ -258,7 +258,8 @@ If the response of the GraphQL operation is an event stream, subsequent values may contain a string field `label`. This `label` is the same label passed to the `@defer` or `@stream` directive that triggered this value. This allows clients to identify which `@defer` or `@stream` directive is associated with -this value. +this value. `label` will not be present if the corresponding `@defer` or +`@stream` directive is not passed a `label` argument. ## Serialization Format