-
Notifications
You must be signed in to change notification settings - Fork 2k
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: allow experimental customization of execution algorithm #3163
Conversation
b268b87
to
84b2657
Compare
It might make sense to export more/all of the functions within the default field executor so that a custom executor could call them as necessary with modifications, but I suppose one could argue that such a move would reveal too much internals... any thoughts? |
dd54cf6
to
d027428
Compare
@yaacovCR Thanks for the PR 👍 I'm asking since it can overlap with our plan to add support for field-level middlewares. |
Do you mean #1516 ? consensus there seems to be to implement middleware in user land. What I am proposing here is to allow execution hooks to allow similar customization of execution pipeline in user land as well. I don’t mind postponing merging, my general thought is to merge as fast as possible, with the caveat that you go slow enough to merge the correct design... So just putting aside when to merge, let’s jumpstart the discussion right now in terms of this PR and that issue. What are the plans for middleware and does this PR complement those plans or conflict or both? |
A use case for gateway would be to skip the getArgumentValues because you don’t need to validate the arguments if you are forwarding to graphql subservice, same in terms of coercion portion of completion. another use case would be to just add debug timings for execution, resolution + completion, ie resolution of the whole tree |
Another use case is to allow passing custom things into parent alter execution of child, ie if the parent has external graphql data, resolve that differently including user land version of graphql Java concept DataFetcherResult https://www.graphql-java.com/blog/deep-dive-data-fetcher-results/ I basically am working in graphql-tools on a similar type that works with defer/stream as well |
Some of this might be Nice to embed within schema object, but I ran into circular type dependency that schema generation code then needs to reference execution code. so I stitched to just global option on execute/graphql functions any ideas there? |
@yaacovCR You need to do coercion of input args and validation of output in terms of query that gateway receives
Yes, this is exactly the use case for middleware together with logging profiling, aborting long execution, etc.
Can be a good solution, can you please explain what was the issue in more detail? |
|
The spec has a must in terms of error path, but just a should in terms of location. Not really clear on the difference for my purposes. |
So idea is that I'm open to wrapping stuff like resolvers if it doesn't affect performance too much. Another possible approach would be to convert the executor functions into class and expose it as "unstable" API, graphql-js/src/language/parser.ts Lines 171 to 179 in 9a04b4c
That said I still don't fully understand the problem that you trying to solve with change. |
Please elaborate on your potential alternative middleware approach that you alluded to above, here, or somewhere else. You wrote originally that one reason for postponing implementing this change is that it may conflict with that feature. But this is that feature, or at least one implementation of it. What potential alternative is it competing with? I think that discussion should take place on GitHub, either here or at #1516, rather than on slack.
If you expose parts of it, but you don't allow users to specify their custom executor and use those parts, it is only half the battle.
This would be fine, although I don't see the difference in exposing a class that is experimental vs a set of functions.
I listed several use cases above. I think the submission stands on its own, although I would be happy to discuss this issue and any other issue on Slack at any time of your convenience. I agree that if you implement custom executors incorrectly, they could break the spec -- the custom executor would be just as responsible as the main package code to implement the spec correctly. It seems a bit heavy handed to forbid users of this package to try their hand at that, however. Any useful experimentation that is open-source could then be submitted upstream, which would be my ideal. |
Don't have anything concrete right now, I'm just worried that instead of solving use cases of end-users we expose some internal functionality. I would rather put effort into adding proper middleware support instead of maintaining a set of "internal hooks" like
Agree, the core issue here is there are multiple libraries that need to alter execution in some way and many of those are pretty unique e.g. graphql-jit previously they used a bunch of "internal" APIs but now it looks like they resorted to copy-paste bunch of source code. The key factor here is that different libraries need to customize different parts of the execution algorith so to satisfy them we basically need to expose a number of "internal hooks" similar to So I think it's better to focus on refactoring out useful bits and pieces like A good example is graphql function (also it real one people actually asked me about adding hooks there), instead of allowing you to replace parser, validator, etc. you can just reuse those parts and write your own version of That said I think we need to have the possibility for people to do rapid prototyping and pushing boundaries of GraphQL so that why I suggest exposing the internals of
You can override methods on the class and have other methods to call overridden method. class CustomExecutionContext extends ExecutionContext {
construct(args: ExecutionArgs) {
super(args);
// ...
}
executeField(/* ... */) {
// you can access super.executeField if you need
// or write your own implemenation
}
}
function customExecute(args: ExecutionArgs) {
const executeContext = new ExecuteContext(args);
return executeContext.executeOperation(args.operationName);
} Would it work for your use case? P.S. You are completely right, that we need to discuss this stuff publicly and not on Slack since there no document explaining architecture stuff like this one. I just find it easier to explain it verbally but totally agree that is not scalable and doesn't help other contributors. |
I’m not quite sure why a class appeals to you more, but as I said above, it’s the same for me, and that sounds absolutely perfect for my needs. thank you so much!!!! |
allows customization of the execution algorithm by overriding any of the protected members of the now exported internal Executor class. Reference: graphql#3163 (comment) Note: This class is exported only to assist people in implementing their own executors without duplicating too much code and should be used only as last resort for cases requiring custom execution or if certain features could not be contributed upstream. It is still part of the internal API and is versioned, so any changes to it are never considered breaking changes. If you still need to support multiple versions of the library, please use the `versionInfo` variable for version detection.
allows customization of the execution algorithm by overriding any of the protected members of the now exported internal Executor class. Reference: graphql#3163 (comment) Note: This class is exported only to assist people in implementing their own executors without duplicating too much code and should be used only as last resort for cases requiring custom execution or if certain features could not be contributed upstream. It is still part of the internal API and is versioned, so any changes to it are never considered breaking changes. If you still need to support multiple versions of the library, please use the `versionInfo` variable for version detection.
allows customization of the execution algorithm by overriding any of the protected members of the now exported internal Executor class. Reference: graphql#3163 (comment) Note: This class is exported only to assist people in implementing their own executors without duplicating too much code and should be used only as last resort for cases requiring custom execution or if certain features could not be contributed upstream. It is still part of the internal API and is versioned, so any changes to it are never considered breaking changes. If you still need to support multiple versions of the library, please use the `versionInfo` variable for version detection.
allows customization of the execution algorithm by overriding any of the protected members of the now exported internal Executor class. Reference: graphql#3163 (comment) Note: This class is exported only to assist people in implementing their own executors without duplicating too much code and should be used only as last resort for cases requiring custom execution or if certain features could not be contributed upstream. It is still part of the internal API and is versioned, so any changes to it are never considered breaking changes. If you still need to support multiple versions of the library, please use the `versionInfo` variable for version detection.
@yaacovCR I need to review both #3184 and #3185 but from a quick look, they look good in general. |
note that the Parser class is contained in lowercase parser.ts
allows customization of the execution algorithm by overriding any of the protected members of the now exported internal Executor class. Reference: graphql#3163 (comment) Note: This class is exported only to assist people in implementing their own executors without duplicating too much code and should be used only as last resort for cases requiring custom execution or if certain features could not be contributed upstream. It is still part of the internal API and is versioned, so any changes to it are never considered breaking changes. If you still need to support multiple versions of the library, please use the `versionInfo` variable for version detection.
allows customization of the execution algorithm by overriding any of the protected members of the now exported internal Executor class. Reference: graphql#3163 (comment) Note: This class is exported only to assist people in implementing their own executors without duplicating too much code and should be used only as last resort for cases requiring custom execution or if certain features could not be contributed upstream. It is still part of the internal API and is versioned, so any changes to it are never considered breaking changes. If you still need to support multiple versions of the library, please use the `versionInfo` variable for version detection.
Closed in favor of #3185, which takes up the above suggestion. |
see: #3163 (comment) depends on #3184
see: #3163 (comment) depends on #3184
See: #3163 (comment) below.
This PR has been reworked on the basis of that suggestion.
Depends on: #3184 and #3185