This document sketches out the potential goals that a proposed solution might attempt to fulfill.
Criteria have been given a "score" according to their relative importance in solving the problem laid out in this RFC while adhering to the GraphQL Spec Guiding Principles. The scores are:
- Critical - The WG has determined that these are the most critical criteria. Any solution that does not meet this criteria will not be considered.
- Major - The WG would strongly prefer that the accepted solution meets this criteria.
- Minor - A nice-to-have
🎯 A. Clients must be able to determine when all fields under a deferred fragment have been delivered.
Score: Critical
Product developers are expected to put all fields that should be deferred together in the same deferred fragment. Clients must be able to determine both when a given grouping of fields have been delivered, so it can notify the associated product code.
Score: Critical
If a field is in both a deferred and non-deferred part of the operation, or in two ore separately deferred parts of an operation, the GraphQL server must not execute this field more than once.
Score: Critical
Clients must be able to apply all subsequent responses to the initial result to create a fully reconciled version of the GraphQL response. For each path in the fully reconciled response, there must be only one value.
Score: Major
If we deliver full selection sets for each unique defer, the amount of data we
deliver could be many times higher than if the @defer
is ignored - not just
the redundant data from the selection sets but the path data used to identify it
in the payload. A situation like this issue can be replicated without
defer/stream by having many aliased copies of friends
in the query, but this
is arguably easier to guard against.
See: #52 (comment)
Score: Minor
Servers should not send payloads to the client that are not actionable. An
example of this is if the server sends some of the fields from a deferred
fragment, while other fields are not yet ready. This data is not actionable to
the client because it must wait for the entire fragment to be completed before
it can notify the product code that the deferred fragment is ready (see
Criteria A
).
Score: Major
All fields queried in a fragment must be delivered together. The "typename hack"
(an unique alias on the __typename
field) is a method to determine if a
GraphQL fragment has been fulfilled.
Example:
{
me {
id
avatarUrl
}
...Stats @defer
}
fragment Stats on Query {
Footer: __typename
me {
friends {
totalCount
}
}
}
Clients must be able to use the presence of "Footer": "Query"
to determine
that the entire Stats
fragment has been delivered.
Score: Major
Product developers should be able to defer fields independently, either by placing them in separate deferred fragments or via another method. These independently deferred fields should be delivered when they are ready, without being blocked by the execution of one another. Solutions that merge deferred fragments with the same path or label will pass this criteria as they still provide a mechanism to allow fields to be independently deferred.
Score: Major
A server should be able to inline a given defer directive, i.e. treat it the
same as if it's if
argument was set to false
. Possible reasons for this
include, but are not limited to
- Not degrading server performance
- a server determining it would lead to better client performance if the deferred data was inlined
- the deferred fields are proxied to a different GraphQL server that does not support defer
Score: Minor
A server should be able to start executing deferred fields without waiting until the entire initial result is complete. If a server is required to wait, it could stretch out the execution time of a single operation by many times the amount of time spent on a similar operation without defers.
Score: Minor
It should be simple for a client to apply incremental results without requiring many deep object merges.
Score: Minor
Since it is not possible to travel back in time to null out previously sent results, error bubbling should work in an intuitive way
Score: Minor
Clients should not be required to add fields like __typename
to deferred
fragments able to understand when this fragment has been delivered. Metadata
like path
and label
should uniquely identify which defer the delivered data
is associated with.
Score: Minor
The same fields should not be delivered to the client multiple times, unnecessarily increasing the data transferred.
Score: Minor
Incremental results should be able to be batched, and clients should be able to apply all of the batched updates before triggering a re-render.
Score: Minor
Predicable payload shapes are beneficial for statically typed clients
Score: Minor
A close representation of the fragment response should be returned in payloads, allowing clients to render directly from the incremental responses without building on prior results.
Score: Minor
The GraphQL spec says on field ordering
Serialization formats which represent an ordered map should preserve the order of requested fields as defined by CollectFields() in the Execution section. Serialization formats which only represent unordered maps but where order is still implicit in the serialization’s textual order (such as JSON) should preserve the order of requested fields textually.
A solution meets this criteria if the final reconciled object preserves the order of requested fields as defined by CollectFields().