dotansimha / dotansimha/graphql-code-generator
Allow plugin to extend the configuration object
- Dominant language
- TypeScript
- Stars
- 11.3k
- Forks
- 1.4k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 23
Description
### Is your feature request related to a problem? Please describe.
I want to have a plugin modify the current config/options object that will be passed down to the next plugins.
My goal is to use graphql directive on fields that will affect how these fields are generated.
More specifically I have the 2 following directives
```graphql
# Resolving a dataloaded field cannot use services other than dataloaders
directive @dataloaded on FIELD_DEFINITION
# Resolving a sync field cannot use services
directive @sync on FIELD_DEFINITION
type User {
id: Int! @sync # Cannot use services to resolve, has to be synchronous
name: String! @dataloaded # Can only use dataloaders, no direct access to database
items: [Item!] # Has full access to database and other services
}
```
In short, these directives allow me to document the schema on how the fields are resolved
I can then use this to statically analyse our queries to make sure we don't add new [N+1](https://medium.com/the-marcy-lab-school/what-is-the-n-1-problem-in-graphql-dd4921cb3c1a)s when these fields are queried inside a list
However, I need to ensure the resolver respects the contract, otherwise this is for nothing.
My solution is to have a plugin consume these directives before the `typescript-resolvers` plugin and inject the [`fieldContextTypes` ](https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-resolvers#fieldcontexttypes) config
Depending on which directive is present, the resolver type will have a different context's type. I can also control if the ReturnType can be asynchronous with the following
```ts
type Impl = {
[field in keyof R]-?: field extends "__resolveType"
? R[field]
: R[field] extends Resolver | undefined
? (
parent: Data,
args: Args,
// prettier-ignore
context:
"Dataloaded" extends Context ? GraphQLContextOnlyLoaders
: "Synchronous" extends Context ? GraphQLContextSynchronous
: GraphQLContext,
info?: GraphQLResolveInfo,
) => "Synchronous" extends Context ? Ret : Promise | Ret
: never;
};
```
### Describe the solution you'd like
I'd like to add a new optional method on the graphql-codegen plugin that can modify the config/options after transforming documents but before executing the plugins
I'd add the following method:
```ts
export interface CodegenPlugin {
plugin: PluginFunction;
addToSchema?: AddToSchemaResult | ((config: T) => AddToSchemaResult);
validate?: PluginValidateFn;
+ extendConfiguration?: (schema: GraphQLSchema, options: {documents: Types.DocumentFile[], config: Types.PluginConfig, plugins: Types.ConfiguredPlugin[]}) => Promise | void;
}
```
and then run those here with
```ts
for (const plugin of pluginPackages) {
if (typeof plugin.extendConfiguration === 'function') {
await plugin.extendConfiguration(schemaInstance, options)
}
}
```
https://github.com/dotansimha/graphql-code-generator/blob/6621759cbb407c3e6d0702890a442505f80d118f/packages/graphql-codegen-core/src/codegen.ts#L130-L146
### Describe alternatives you've considered
The only other alternative I've found is to manually list the necessary config for the typescript-resolvers plugin in my config.
However, that would not be driven by the directive and I'd need an extra layer of verification to make sure they're aligned.
I don't want to have to duplicate the information and explode the config with an enormous list that impossible to maintain.
### Is your feature request related to a problem? Please describe.
_No response_
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.