graphql-php icon indicating copy to clipboard operation
graphql-php copied to clipboard

Support Defer and Stream Directives

Open arnaud-lb opened this issue 2 years ago • 7 comments

Hi,

The DeferStream RFC describes a mechanism to deliver some parts of a query response incrementally:

This proposal would introduce @stream and @defer directives which clients could use to communicate the relative priority of requested data to GraphQL implementations. Furthermore this proposal would enable GraphQL APIs to split requested data across multiple response payloads in order of priority. The goal of this proposal is to enable applications to reduce latency without increasing server cost or resource contention.

Quoting apollo-server:

These directives allow clients to specify that parts of an operation can be sent after an initial response, so that slower fields do not delay all other fields.

The RFC is still a working draft, but it's implemented by relay, graphql-js (PR), apollo-server (PR).

On the transport level, servers can use a multipart response: https://github.com/graphql/graphql-over-http/blob/main/rfcs/IncrementalDelivery.md

It would be nice if this library implemented DeferStream. This can considerably simplify some data fetching patterns.

arnaud-lb avatar Sep 25 '23 15:09 arnaud-lb

I am not planning to work on this myself, but am generally open towards implementing ongoing RFCs or experimental features and would accept a pull request for this.

spawnia avatar Sep 26 '23 13:09 spawnia

Would the support for @defer requires the use of something like Swoole ? Or would it be also possible with the traditional short-lived PHP process?

PowerKiKi avatar Oct 03 '23 12:10 PowerKiKi

It is not necessary, but might be better to increase the amount of possible concurrent queries.

Also, I remembered that Lighthouse already supports @defer. You might use https://github.com/nuwave/lighthouse/tree/master/src/Defer as inspiration for the implementation.

spawnia avatar Oct 04 '23 09:10 spawnia

In this case the barrier for entry would be pretty much null, and this feature could interest a lot of people, including myself 🤩

PowerKiKi avatar Oct 04 '23 13:10 PowerKiKi

I'll try to do it on my free time.

I wrote some lines today, and when a walk through the code; I can see that all existing directives are added by default in the schema definition. So I followed the same logic by adding:

// BuildSchema::buildSchema()

if (! isset($directivesByName[Directive::DIRECTIVE_DEFER_NAME])) {
    $directives[] = Directive::deferDirective();
}

But since it's an "experimental" feature, wouldn't it be better not to add it by default? Can result in something like:

$schema = new Schema(
    (new SchemaConfig())
    ->useDeferExperimentalDirective()
);

Another question that I've in mind (cc. @spawnia): Can you explain me the purpose of QueryComplexity::directiveExcludesField ? When I compare the code with graphql-js or lighthouse, that's something I can't find in how they're implemented. Thank you so much for your time :)

MaelitoP avatar Jan 14 '24 19:01 MaelitoP

Yeah, making @defer opt-in seems right.

QueryComplexity::directiveExcludesField determines if the given field will be executed at all, given the directives placed upon it. For example, if it has @skip(if: true) on it, it will not actually run.

spawnia avatar Jan 15 '24 15:01 spawnia

I'm interested in the stream directive, mostly to reduce the memory usage of the server when resolving large lists of nested json data. In this case the data is a little hard to paginate

aszenz avatar Apr 30 '24 15:04 aszenz