Skip to content
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

Spec edits for incremental delivery, Section 3 only #1132

Open
wants to merge 5 commits into
base: incremental-integration
Choose a base branch
from

Conversation

robrichard
Copy link
Contributor

@robrichard robrichard commented Jan 7, 2025

Extracted from the full PR (#1110) and targeting an integration branch to aid in review.

Helpful reference material:

Response format examples: graphql/defer-stream-wg#69
Glossary: graphql/defer-stream-wg#106
GraphQL Conf talk: https://www.youtube.com/watch?v=LEyDeNoobT0

yaacovCR pushed a commit to graphql/graphql-js that referenced this pull request Jan 12, 2025
Updated to reflect spec draft
graphql/graphql-spec#1132

Also changed the argument order to match the spec draft
@robrichard robrichard requested a review from benjie January 30, 2025 19:56
Copy link
Member

@benjie benjie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of nit-picky comments but I think we're pretty close! Do we have a glossary somewhere? I think we need to be really crisp on terms like "result", "response", "payload" and the like.

Comment on lines 2188 to 2189
responses: the initial response containing all non-deferred data, while
subsequent responses include deferred data.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that we've refined the terminology around this: there's one response. The response for stream/defer is a stream consisting of an initial result payload followed by a number of incremental payloads. I couldn't find where we discussed this, so please correct as appropriate.

Suggested change
responses: the initial response containing all non-deferred data, while
subsequent responses include deferred data.
payloads: the initial payload containing all non-deferred data, while subsequent
payloads include deferred data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benjie after the last discussion we had, I decided to drop payload. The response section now says:

The result of a GraphQL request must be either a single initial response or an
incremental stream. The response will be an incremental stream when the GraphQL
service has deferred or streamed data as a result of the @defer or @stream
directives. When the result of the GraphQL operation is an incremental stream,
the first value will be an initial response, followed by one or more subsequent
responses.

corresponding defer directive. If provided, the GraphQL service must include
this label in the corresponding pending object within the response. The
`label` argument must be unique across all `@defer` and `@stream` directives
in the document.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the use of "response" here is probably fine, but feel free to change it to be more crisp. Either way, we should explain why variables are disallowed:

Suggested change
in the document.
in the document.
Note: Variables are disallowed in the `label` because...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this note below the @stream section and worded it so it applies to both @defer and @stream.

Comment on lines 2230 to 2233
The `@stream` directive may be provided for a field whose type incorporates a
`List` type modifier; the directive enables the backend to leverage technology
such as asynchronous iterators to provide a partial list initially, and
additional list items in subsequent responses.
Copy link
Member

@benjie benjie Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've extracted the part about iterators to a non-normative note and added text about nested lists.

Suggested change
The `@stream` directive may be provided for a field whose type incorporates a
`List` type modifier; the directive enables the backend to leverage technology
such as asynchronous iterators to provide a partial list initially, and
additional list items in subsequent responses.
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 subsequent payloads. Should the field type
incorporate 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I applied this change, only updating subsequent payloads to subsequent responses.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"response" is already a well defined term in the GraphQL spec: https://spec.graphql.org/draft/#sec-Response - essentially it's the {data?: {...}, errors?: GraphQLError[]} object. We should be careful not to confuse it with other objects such as the incremental payload objects.

Comment on lines 2252 to 2254
- `initialCount: Int! = 0` - The number of list items the service should return
initially. If omitted, defaults to `0`. A field error will be raised if the
value of this argument is less than `0`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `initialCount: Int! = 0` - The number of list items the service should return
initially. If omitted, defaults to `0`. A field error will be raised if the
value of this argument is less than `0`.
- `initialCount: Int! = 0` - The number of list items to include in the initial
result payload. If omitted, defaults to `0`. A field error will be raised if
the value of this argument is less than `0`.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated this to The number of list items to include initially.. I originally had something similar but there was feedback in one of the prior PRs that we shouldn't say initial response since @stream may be used inside of a @defer. The initial items in this case would not be returned in the initial response.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good subtle catch. "Initially" is a bit weakly defined though; perhaps "The number of list items to include initially when completing the parent selection set." or something along those lines? I'm not happy with the term "completing" nor "resolving" here, mind. 🤔

Comment on lines 2255 to 2257
- `if: Boolean! = true` - When `true`, field _should_ be streamed (see related
note below). When `false`, the field must not be streamed and all list items
must be initially included. Defaults to `true` when omitted.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "and" here implies this is an additional behaviour

Suggested change
- `if: Boolean! = true` - When `true`, field _should_ be streamed (see related
note below). When `false`, the field must not be streamed and all list items
must be initially included. Defaults to `true` when omitted.
- `if: Boolean! = true` - When `true`, field _should_ be streamed (see related
note below). 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` when omitted.

Comment on lines 2261 to 2263
this label in the corresponding pending object within the result. The `label`
argument must be unique across all `@defer` and `@stream` directives in the
document.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this label in the corresponding pending object within the result. The `label`
argument must be unique across all `@defer` and `@stream` directives in the
document.
this label in the corresponding pending object within the response. The
`label` argument must be unique across all `@defer` and `@stream` directives
in the document.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we forbidding multiple occurrences of the same field with a @stream directive (even if directive arguments match)? If not:

{
  friends @stream(label: "A") { id }
  friends @stream(label: "A") { name }
}

fails this text, I think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of graphql/defer-stream-wg#100 this is no longer allowed so I think this is ok?

Comment on lines 2272 to 2275
that ignores the `@defer` and/or `@stream` directives. This also applies to the
`initialCount` argument on the `@stream` directive. Clients _must_ be able to
process a streamed response that contains a different number of initial list
items than what was specified in the `initialCount` argument.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to make it clear that each @stream or @defer may be ignored independently of the others.

Suggested change
that ignores the `@defer` and/or `@stream` directives. This also applies to the
`initialCount` argument on the `@stream` directive. Clients _must_ be able to
process a streamed response that contains a different number of initial list
items than what was specified in the `initialCount` argument.
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 response that contains a different number of initial
list items than what was specified in the `initialCount` argument.

I've also removed the italics from _must_ because this is explicitly a non-normative note, and shouldn't have conformance requirements in it. If this is a conformance requirement that isn't stated elsewhere, it needs to be moved outside of the Note:.

I also think that the final sentence is worded a bit weakly... Can the server return any number of results initially, followed by any number of results in follow up payloads? I personally don't think this is ideal. If a client says @stream(initialCount: 2) then I think the server should either return at least two results in the initial result payload, and stream others; or not stream the result at all. If servers want to be able to always stream zero results they should add a lint rule to force initialCount to always be omitted or = 0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we had consensus in the primary WG on graphql/defer-stream-wg#104, i have updated the initialCount section above to include:

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 related note
below).

With this text, I think it is safe to remove italics from must. I believe this note is now just stating client consequences of server behavior that is described earlier.

Additionally I updated "contains a different number of initial list items" to "contains more initial list items"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, because if it has fewer list items it's not a "streamed response"? Good thinking.

We should clarify that "response" doesn't mean the response as a whole, but just that from the field. Perhaps "streamed field response"/"streamed field result"?

@robrichard robrichard force-pushed the incremental-integration-type-system branch from d5322ae to 32785b8 Compare February 7, 2025 20:33
@robrichard
Copy link
Contributor Author

@benjie I added a rough glossary here: graphql/defer-stream-wg#106, I'll keep refining it as we go

@robrichard robrichard requested a review from benjie February 24, 2025 19:38
@robrichard robrichard force-pushed the incremental-integration-type-system branch from 6334cd2 to 176172f Compare February 24, 2025 19:40
@robrichard robrichard force-pushed the incremental-integration-type-system branch from 176172f to 7c0ba73 Compare February 24, 2025 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants