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
[RFC] Plugin system #200
[RFC] Plugin system #200
Conversation
* develop: Fix inline functions for custom scalars (#174) Fix types in Ghost example Fix nexus-prisma doc title and label (#166) [RFR] Allow schema construction even with unknown types (#155) Add docs for nexus-prisma v2 (#164) Fix wrong fieldName type on subscriptionField (and fix backingTypes.spec.ts) (#159)
Hey @tgriesser, few things on my mind;
CC @Weakky |
[1] I'm not sure what |
@Weakky and I can help with this. I see that all the test suite stuff related to dynamic outputs for example can be extracted to its own PR. I haven't dived into this PR yet, so maybe it will be obvious, but probably it will help if you can outline some of the parts of this PR that definitely should be factored out : ) Also, rebasing this PR atop |
Yep, that would be the api (the
I'm working on another branch which is manually picking off the relevant bits from this branch and using some of the integration test tooling you added to create an example with all of the intended features. Will have something to demonstrate this in the next few days.
It might not be worth it at this point to dive too into this PR in its current state - I pulled out some bits in #225 that were in here to improve the overall code coverage. There are a few other pieces, like minor non-breaking type changes that could be extracted out as well to keep the plugin diff as minimal as possible.
Don't worry about it - this branch has a bunch of things happening at once, and has diverged quite |
This is interesting, and a bit different use case than what I had been thinking of for plugins - though it's perfectly valid and I don't see any reason why it wouldn't be possible. I think we might need to cleanup and add a formalized "public" API for the internal |
This comment has been minimized.
This comment has been minimized.
@tgriesser btw let me know if there's a better place to have this conversation :) |
@tgriesser ignore my latest comments as they are superseded by on subsequent slack chats and the spec in notion. |
@tgriesser In light of #242 should we close this one? |
Yep, that sounds good |
This is a WIP branch for a plugin system that will allow us to tap in and extend the core behavior and execution of Nexus resolvers at several levels of the schema construction.
The plugin system will:
This approach means we can dynamically add type-safe additions to the augment the options accepted at the schema, type, or field level. The specifics for how this will work best around type-merging are still being determined, and still requires some refactoring of the current generated types.
The behavior will depend on how we wrap the
resolve
method. Current thinking is that the plugins will operate first-to-lastbefore
the field resolver, and last-to-first for theafter
hook of the resolver:will execute the "chain":
Each plugin will have a
pluginDefinition
definition block, which may return a plain object with abefore
orafter
property (or both). The before will execute before the resolver, and has a signature of:Returning
nextVal
, a plain object frozen withObject.freeze
will signal the execution to continue to the next item in the execution list. Returning another value will cause that to be the resolved value for the next item in the chain.The
after
has a similar signature, with the addition of theresult
as the first member, andbreakVal
as the final member.Returning
breakVal
will early-exit from the rest of the items in the chain. Returningundefined
will continue to the next member in the chain. Returning any other value will replace the currentresult
value as it continues through the execution chain.The naming of these is subject to change, and some of the implementation may change as we evaluate the real-world needs of plugins we aim to implement.
To understand how this would work in practice, let's take a look at an example of field-level authorization, something which is baked in the library, but could (and will be) implemented purely as a plugin:
The
fieldDefTypes
will be added to a globalNexusGenPluginFieldConfig
which is implemented as part of the object field options typing. Anauthorize
field is now made available for us, and if provided will be called before the field is resolved to check whether it is authorized.This PR will also aim to include several common plugins as core offerings along side of this feature:
Also, possibly:
There are a lot of changes in this branch, because when I initially had started on it, I had begun to refactor a few internal pieces as well. Given the scope of the changes for plugins, however, I will also look to open smaller PRs separately to handle those refactors. Aiming to have the work on plugins completed by the end of Sept.
Any feedback/questions is welcome!