Replies: 5 comments
-
To clarify: I am not suggesting that incremental delivery be postponed until after the fragment modularity proposal is accepted in its entirety. I am suggesting that an idea from the fragment modularity proposal, aliased fragment spreads, be folded into incremental delivery. Aliased fragment spreads may be the form that fragment modularity eventually takes, or that proposal may take a different path, but that particular idea works extremely well with incremental delivery. At this stage, it might be appropriate to both require (1) that whenever the defer directive is used, there is also an alias fragment as well as (2) that whenever an aliased fragment is used, defer is also present. Requirement (2) could be relaxed as further specified by the fragment modularity proposal. |
Beta Was this translation helpful? Give feedback.
-
As semi-sort-of-suggested by @glasser at the last WG, I have been working on spec edits for a version of incremental delivery that both provides fragment notification, but also does not branch execution or duplicate fields. This may end up being powered by "references" an alternative syntax for metafields like |
Beta Was this translation helpful? Give feedback.
-
One way we could make aliased fragments "work" without duplicating data unnecessarily is to introduce the concept of a "link" or "pointer" type for them. Basically, the response could look like:
Basically the named fragment gives you a hook to where the child fields are located. If the fragment is already fulfilled by what was requested, that hook is "this" or something like that. If the fragment is not going to be fulfilled at all (due to some error bubbling up or what not), it could be |
Beta Was this translation helpful? Give feedback.
-
Another interesting discussion that @yaacovCR brought up is the batching problem: combining multiple nested However, we could imagine a world where we desire a way to annotate subsets of our response as being low-reliability. This is essentially extreme defer/stream: you want to be able to fulfill the data when it's cheap to do so or it's needed right now, but if it'll be expensive you just don't do the work until the client explicitly requests that you do it. To accomplish this, I think we'd want some sort of "continuation token" that the server can recognize as a starting point for resuming work. Fragment-alias "links" could provide such a starting point (for defer), and we could re-use the concept of links within list streams if we treated the list field as the linking point. Realistically we could also support field-level defer this same way. In this world, we'd be able to have an original response from the server like:
Basically saying "Yeah we said there's more data, but this server is at capacity and doesn't want to give you any more until you need it". Then the client could send a request back with:
and receive the extremely deferred payload:
|
Beta Was this translation helpful? Give feedback.
-
Significant work on deduplication has made this proposal superfluous! See: And older efforts: |
Beta Was this translation helpful? Give feedback.
-
Suggestion
Require that defer is only used on aliased fragments (see https://github.com/graphql/graphql-wg/blob/main/rfcs/FragmentModularity.md#syntax-1-aliased-spreads-foo-foo).
Advantages:
Disadvantages:
@defer
directive is not respected, i.e. the fragments are "inlined," because a server perhaps the data available in cache or for some other reason determines that the response would be faster by inlining the data.In particular, the suggestion is to require an alias like the below to use
@defer
:Worked Example
Current Behavior: A Simple Example
The operation below is taken from the current incremental delivery test examples:
And results in the following response stream if the
@defer
directive is respected as is recommended:But could also result in the following single response if the initial data and the deferred data is available simultaneously, the server is aware of this, and the server therefore choose to "ignore" the
@defer
directive:Note that in the above case, the deferred fragment data is merged with the original data so that the
id
field is sent only once, which is desirable. Note also that the single response does not make it clear that the deferred response was sent "early." This can be inferred, of course, from the fact that only a single result was sent, andhasNext
is obviously false. But what would happen if two fragments were sent, and only one deferred, as in the next case?Current Behavior: Multiple Deferred Fragments
Which could result in the following response stream if
@defer
is fully respected:Or the following response stream if
TypeFragment
is inlined in the initial payload:Or the following response stream if
NameFragment
is inlined in the initial payload:Note that in the latter two scenarios, even were a "label" argument to be used by the
@defer
directive, when payloads are inlined inside the initial response, the included labels are not included. In fact, it may be quite bulky for the response to specify which spreads have been inlined -- when the initial response contains a list of objects, each with deferred fragment spreads, the spreads that have been inlined for each object may differ, requiring specification of the included labels on a per-item basis.Proposed Behavior: Multiple Deferred Fragments
Which could result in the following response stream if
@defer
is fully respected:Or the following response stream if
TypeFragment
is inlined in the initial payload:Or the following response stream if
NameFragment
is inlined in the initial payload:Note:
The weakness of this proposal is that when a deferred fragment is now "inlined," fields (i.e. the "id" field above) may be repeated. This weakness is also a strength, in that this repetition powers the stability of the types of all fields. If the aliased fragment is present at any stage, it has a predictable shape, and it is the shape itself -- rather than any additional metadata -- that describes which spreads have been included. (Labels are obviated!) This addresses the initial concern raised by @IvanGoncharov #52.
Note:
The alias for the deferred fragment is not included in the
path
of the payload, but within the data itself such that if multiple deferred fragments are available at the same time, they can be sent simultaneously. This addresses the case raised by @benjie in #52 (comment) and parallels how the array syntax for streamed fields with@stream
will allow for batching multiple available results (although this is not yet specified). This makes intuitive sense, in that the use of@defer
implies a stream of the parent object field, just like@stream
on an list field, with the difference that an "object stream" allows streaming of multiple deferred fragments in any order, while a "list stream," at least by default, has an order. In particular, the below response stream should also be valid:Beta Was this translation helpful? Give feedback.
All reactions