-
Notifications
You must be signed in to change notification settings - Fork 238
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
feat: @defer support #898
base: next
Are you sure you want to change the base?
feat: @defer support #898
Conversation
…20824 accept header
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a amazing on multiple level! Deferred resolver is massive new feature coming in graphql v17!
(Given that this PR is also made possible by Readable.from() and node stream iterator support... I'm even more in awe. I championed and implemented those features).
I'm a bit concerned how we could land this and let people experiment about it for now.
It's better if we put @defer
under an option. This will allow to throw if jit is enabled or it's missing graphql-jit.
test/directives.js
Outdated
'multipart/mixed; deferSpec=12345' | ||
] | ||
|
||
for (const accept of wrongAcceptValues) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move this for loop outside of the test definition
test/directives.js
Outdated
content-type: application/json; charset=utf-8\r | ||
\r | ||
{"hasNext":false,"incremental":[{"path":["allProducts",0,"delivery"],"data":{"estimatedDelivery":"25.01.2000","fastestDelivery":"25.01.2000"}}]}\r | ||
-----\r |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also add a test using undici.fetch()? It should work and support multipart responses.
…removed unnecessary status code in the error
index.js
Outdated
) { | ||
// The client ran an operation that would yield multiple parts, but didn't | ||
// specify `accept: multipart/mixed`. We return an error. | ||
throw new Error( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please create an error in https://github.com/mercurius-js/mercurius/blob/master/lib/errors.js and use it here
test/defer.js
Outdated
directive @defer( | ||
if: Boolean! = true | ||
label: String | ||
) on FRAGMENT_SPREAD | INLINE_FRAGMENT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this directive added automatically by mercurius?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would do this behind a defer: true
option, set to false by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @mcollina I've added opts.defer
, but I'm not quite sure if we really need that, since we decided to cut this off to a new release branch where we assume @defer
will be available to everyone.
I can remove opts.defer
and just leave its directive definition so that we always have this functionality with graphql@17
.
What do you think?
How could I ship this today and keep the current dependency at |
I didn't update any gql-related dependencies in So I think it's safe to ship this once I incorporate the feedback and CI is green. Appreciate if you can help with the things you mentioned - otherwise I'll do this later today 🙂 |
package.json
Outdated
@@ -64,6 +64,7 @@ | |||
"graphql": "^16.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we are not testing this behavior in CI, right? We should. The peerDependency
might not be correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could try adding CI tests that install graphql@17
if you can point me to the right direction - how and where you add them?
Also, what do you mean by peerDependency not correct
? It didn't change in my PR, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would an end user use defer? As you can see we depend upon graphql
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. So the Apollo Server, as a reference, didn't update graphql version and they will only do that when graphql@17 is released. Until that, it's the change that is implemented and tested on CI, but not available to the end users since it's still in alpha
That being said, the idea of mine was to do the same here - start supporting it but not allow users to use it until graphql@17 is officially released
In the future, when graphql@17 is live, we will update the mercurius dependency and everyone will be able to use defer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to cut a next branch for you, so we can land this with the alpha version of graphql-js.
wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good to me! so i finish the feedback first and then you create a next release branch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I incorporated the feedback and going to see what's going on there with JIT compiler when I have some time
92f04ad
to
274c5bc
Compare
test/defer.js
Outdated
t.teardown(async () => { | ||
await reader.releaseLock() | ||
app.close() | ||
process.exit() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if I wasn't iterating through the stream correctly, but the test never stops - added process.exit()
to make it passing.
@mcollina can you please help here, maybe you see a problem in my code?
@mcollina I believe you saw my issue in |
It's likely better to wait until we hear back, I might be wrong but there is no urgency to ship given graphl@17 is still in alpha. |
Just to clarify: we have released support for defer/stream in Apollo Server 4 (which is now the current major version), but we are considering it experimental for now for various reasons including that it requires unreleased Exciting to see Mercurius implementing it as well! Happy to see you're also requiring the client to opt in with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've rebased this on top of the next branch.
We can land as soon as the tests pass
test/defer.js
Outdated
const mercurius = require('../index') | ||
const { canUseIncrementalExecution } = require('../lib/util') | ||
|
||
if (canUseIncrementalExecution) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This if should not be needed anymore.
@@ -187,6 +189,20 @@ const plugin = fp(async function (app, opts) { | |||
}) | |||
} | |||
|
|||
if (opts.defer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you throw if jit is enabled with defer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added an error throwing when both jit and defer are enabled & updated the docs to have defer
option there and in typescript definitions
lib/util.js
Outdated
|
||
// istanbul ignore next | ||
function executeGraphql (args) { | ||
if (canUseIncrementalExecution) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should happen only if defer is enabled.
lib/util.js
Outdated
@@ -23,7 +26,26 @@ function hasExtensionDirective (node) { | |||
} | |||
} | |||
|
|||
const canUseIncrementalExecution = !!require('graphql/execution').experimentalExecuteIncrementally |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed, this is always true now.
* Add space between merged SDLs to fix merging errors * Add unit tests for schema merging
* feat: add types for object in graphiql configuration * feat: add test to types
…s-js#900) * Prevent parsing schema extensions * Add unit test
Signed-off-by: Matteo Collina <[email protected]>
…into defer-directive-support
…into defer-directive-support
Thanks! I've made more changes that you requested. I'm going to check if we can get the response from graphql-jit team or I can maybe make the necessary changes in their project, since we're blocked by that. |
I didn't get any response from |
Hi! What needs to be done here to merge this? I’d really like to use this feature so I’ll gladly help. |
I think a public release of GraphQL v17? |
Hi everyone ✋ As some of you may have noticed, apollo and graphql-js added support for
@defer
directive, so it's time to do the same in Mercurius!🤔 What is @defer and why do we need that?
@defer
is a directive that allows you to receive query data incrementally. There is a bunch of information about it but a decent source is Apollo Docs @defer.⌛ Current state of things
@defer
and made it available in[email protected]
@defer
.📦 What this PR does
It uses the new GraphQL incremental api (if it's available! otherwise we use old api for backwards-compatibility) to execute queries.
The incremental api itself does all the magic for us and returns either the classic response
(body.data.myField)
or the incremental one with stream (see more in the api type definitions)Client should send us the following header
accept: multipart/mixed; deferSpec=20220824
in order to get a stream response back. Otherwise, the error is thrown that doesn't allow client to get the data.The PR also moves to a new signature of
GraphQLError
since the old one is deprecated and its support is removed in graphql@17Additionally, it bumps the
graphql-js
to17.0.0-alpha.2
(latest available right now). Once PR has all the tests passed and feedback incorporated, it's going to be cut off to a separate release branch, instead of getting merged to master directly because ofgraphql@17
which is still in alpha🧰 Local development / testing
If you wish to see how it's going to look like in a real app, I've put together an Apollo Client/Server + Mercurius setup that allows you to run a query with
@defer
against either:graphql-jit
is not adopted to usegraphql@17
yet and I asked code owners if they want to make an upgrade GraphQL 17 support? zalando-incubator/graphql-jit#184Please take into account that all the things I mentioned in the PR are my suggestions based on what I've read and heard. I am open to the ideas you might have, especially because it's my first PR to this repository.
I want to give a huge shoutout to the Mercurius team for their amazing hard work maintaining this project and to Apollo team who were the first in
@defer
implementation, and whose examples I've used to implement the changes in this repo.Cheers ✌️