Skip to content
Merged
Changes from all commits
Commits
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
130 changes: 128 additions & 2 deletions spec/Section 3 -- Type System.md
Original file line number Diff line number Diff line change
Expand Up @@ -812,8 +812,8 @@ And will yield the subset of each object type queried:
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.
that are skipped via `@skip` or `@include` directives or postponed via `@defer`.
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 @@ -2084,6 +2084,15 @@ GraphQL implementations that support the type system definition language must
provide the `@deprecated` directive if representing deprecated portions of the
schema.

GraphQL implementations may provide the `@defer` and/or `@stream` directives. If
either or both of these directives are provided, they must conform to the
requirements defined in this specification.

Note: The [Directives Are Defined](#sec-Directives-Are-Defined) validation rule
ensures that GraphQL operations can only include directives available on the
schema; thus operations including `@defer` or `@stream` directives can only be
executed by a GraphQL service that supports them.

GraphQL implementations that support the type system definition language should
provide the `@specifiedBy` directive if representing custom scalar definitions.

Expand Down Expand Up @@ -2321,3 +2330,120 @@ input UserUniqueCondition @oneOf {
organizationAndEmail: OrganizationAndEmailInput
}
```

### @defer

```graphql
directive @defer(
if: Boolean! = true
label: String
) on FRAGMENT_SPREAD | INLINE_FRAGMENT
```

The `@defer` directive may be provided on a fragment spread or inline fragment
to indicate that execution of the related selection set should be deferred. When
a request includes the `@defer` directive, it may return an _incremental stream_
consisting of an _initial execution result_ containing all non-deferred data,
followed by one or more _execution update result_ including deferred data.

The `@include` and `@skip` directives take precedence over `@defer`.

```graphql example
query myQuery($shouldDefer: Boolean! = true) {
user {
name
...someFragment @defer(if: $shouldDefer, label: "someLabel")
}
}
fragment someFragment on User {
id
profile_picture {
uri
}
}
```

#### @defer Arguments

- `if: Boolean! = true` - When `true`, fragment _should_ be deferred (see
[Client Handling of `@defer`/`@stream`](#sec-Client-handling-of-defer-stream)).
When `false`, fragment must not be deferred. Defaults to `true`.
- `label: String` - An optional string literal used by GraphQL clients to
identify data in the _incremental stream_ and associate it with the
corresponding defer directive. If provided, the GraphQL service must include
this label in the corresponding _pending result_ within the _incremental
stream_. The `label` argument must be unique across all `@defer` and `@stream`
directives in the document. Variables are disallowed (via
[Defer And Stream Directive Labels Are Unique](#sec-Defer-And-Stream-Directive-Labels-Are-Unique))
because their values may not be known during validation.

### @stream

```graphql
directive @stream(
if: Boolean! = true
label: String
initialCount: Int! = 0
) on FIELD
```

The `@stream` directive may be provided for a field whose type incorporates a
`List` type modifier. The directive enables returning a partial list initially,
followed by additional items in one or more _execution update result_. If the
field type incorporates multiple `List` type modifiers, only the outermost list
is streamed.

Note: The mechanism through which items are streamed is implementation-defined
and may use technologies such as asynchronous iterators.

The `@include` and `@skip` directives take precedence over `@stream`.

```graphql example
query myQuery($shouldStream: Boolean! = true) {
user {
friends(first: 10)
@stream(if: $shouldStream, label: "friendsStream", initialCount: 5) {
name
}
}
}
```

#### @stream Arguments

- `if: Boolean! = true` - When `true`, field _should_ be streamed (see
[Client Handling of `@defer`/`@stream`](#sec-Client-handling-of-defer-stream)).
When `false`, the field must behave as if the `@stream` directive is not
present—it must not be streamed and all of the list items must be included.
Defaults to `true`.
- `label: String` - An optional string literal used by GraphQL clients to
identify data in the _incremental stream_ and associate it with the
corresponding stream directive. If provided, the GraphQL service must include
this label in the corresponding _pending result_ within the _incremental
stream_. The `label` argument must be unique across all `@defer` and `@stream`
directives in the document. Variables are disallowed (via
[Defer And Stream Directive Labels Are Unique](#sec-Defer-And-Stream-Directive-Labels-Are-Unique))
because their values may not be known during validation.
- `initialCount: Int! = 0` - The number of list items to include initially when
completing the parent selection set. If omitted, defaults to `0`. An execution
error will be raised if the value of this argument is less than `0`. When the
size of the list is greater than or equal to the value of `initialCount`, the
GraphQL service _must_ initially include at least as many list items as the
value of `initialCount` (see
[Client Handling of `@defer`/`@stream`](#sec-Client-handling-of-defer-stream)).

### Client Handling of @defer/@stream

The ability to defer and/or stream data can have a potentially significant
impact on application performance. Developers generally need clear, predictable
control over their application's performance. It is highly recommended that
GraphQL services honor the `@defer` and `@stream` directives on each execution.
However, the specification allows advanced use cases where the service can
determine that it is more performant to not defer and/or stream. Services can
make this determination on case by case basis; e.g. in a single operation, one
or more `@defer` and/or `@stream` may be acted upon while others are ignored.
Therefore, GraphQL clients _must_ be able to process a _response_ that ignores
individual `@defer` and/or `@stream` directives. This also applies to the
`initialCount` argument on the `@stream` directive. Clients must be able to
process a streamed field result that contains more initial list items than were
specified in the `initialCount` argument.