graphql-code-generator-plugins icon indicating copy to clipboard operation
graphql-code-generator-plugins copied to clipboard

[FEAT] Context Type Automatic Detection

Open RichiCoder1 opened this issue 2 years ago • 14 comments

Is your feature request related to a problem? Please describe. Pardon if this is already implemented, but the ability to override the context type in a similar fashion to other type mappings.

Describe the solution you'd like Maybe ContextTypeMapper or even just ContextType

Describe alternatives you've considered Currently using presetConfig.typesPluginConfig.contextType and it's working very well, but wanted to call this out.

RichiCoder1 avatar Jun 01 '23 21:06 RichiCoder1

Good idea @RichiCoder1 ! It's not currently implemented at the moment.

Do you have a suggestion for the file name? 🙂

eddeee888 avatar Jun 02 '23 10:06 eddeee888

Maybe just schema.context.ts? And warn if there are multiple matches with first winning? Would export Context. So basically an automatic schemas/base/schema.context.ts#Context.

RichiCoder1 avatar Jun 04 '23 17:06 RichiCoder1

Nice! I think we are onto something here 🙌

Maybe the export could be ResolversContext to be more explicit?

There's also fieldContextTypes option in typescript-resolvers which could be used to set context on the field level...

So, I'm thinking each module could declare its own schema.context.ts file. For example:

If schema/user/schema.context.ts has Query_userResolversContext (context applicable to user query), then it'd be mapped to: fieldContextTypes: ['Query.user#./schema/user/schema.context.ts#Query_userResolversContext']

eddeee888 avatar Jun 13 '23 10:06 eddeee888

Just to be certain this is what I'm also looking for. This would mean that the ResolversContext type definition in schema.context.ts will be imported by types.generated.ts and hence propagated. Correct?

Curious if this could also result in generating a context "resolver" file similar to what graphql-yoga would expect. But I suppose that's a feature on top of that as well.

karloluis avatar Jun 28 '23 11:06 karloluis

Hi @karloluis ,

This would mean that the ResolversContext type definition in schema.context.ts will be imported by types.generated.ts and hence propagated. Correct?

Yes! That's correct.

You could already use the context type like this when creating GraphQL Yoga server:

const yoga = createYoga<{}, ResolverContext>({ 
  context: { ... }, // <-- Context object/function is typed to `ResolverContext`
});

Each GraphQL server may have a different type for its context "resolver", so I'm not sure we should generate it. 🙂

eddeee888 avatar Jul 01 '23 23:07 eddeee888

Any updates here? Is there any way to specify the context type with this plugin? The docs state to use {config: contextType: 'MyCustomContext'}} but not clear how to integrate that with this plugin's defineConfig()... should the results of defineConfig() be updated with contextType, or is there another way?

EDIT: Nevermind, found it. typesPluginConfig.contextType

0xalecks avatar Jan 21 '24 16:01 0xalecks

It's been a few months and I decided to update to version 0.8.0. Hurray! 🎉

Looking back at the configs I am still stuck on how to configure a default ContextType. My generated types look as follows:

export type QueryResolvers<
  ContextType = any,
  ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'],
> = { ... }

With the use of generates."src/graphql".presetConfig.typesPluginConfig.contextType: "./context.ts#Context" I expected ContextType = any to change to reference the exported type from the file. Sadly that didn't happen and after tinkering around for a bit I have not been able to figure things out. Same could be said if I targeted Resolvers<ContextType = any>.

Is my understanding that the any type should reference the Context type incorrect? Could I be missing something with regards to the ts-resolver plugin?

karloluis avatar May 13 '24 09:05 karloluis

Yes, that's correct @karloluis.

Here's an example repo: https://github.com/eddeee888/graphql-server-template/

  • The context config is here: https://github.com/eddeee888/graphql-server-template/blob/bcf63ee72f59d656257f770978c6ca45cdf4287b/codegen.ts#L12...
  • Which points to this type

eddeee888 avatar May 13 '24 10:05 eddeee888

Well that's awkward. After tinkering with the file a bit more and testing the typesSuffix option to validate that the options were in fact picked up it suddenly started working whereas a few runs ago it didn't seem to do any changes!

I suspect my runtime for codegen was somehow faulty. Maybe bad YAML indentation.

karloluis avatar May 13 '24 10:05 karloluis

Hi there, I ran into this issue as well where my src/schema/types.generated.ts had ContextType of any.

Following your comment to edit the config in codegen.ts did the trick, so thank you 👍

My updated codegen.ts
import { defineConfig } from '@eddeee888/gcg-typescript-resolver-files';
import type { CodegenConfig } from '@graphql-codegen/cli';

export default {
  schema: '**/schema.graphql',
  generates: {
    'src/schema': defineConfig({
      emitLegacyCommonJSImports: false, // enables ESM imports with .js ext
      typesPluginsConfig: {
        contextType: '../index.js#ApolloServerContext',
      },
    }),
  },
} satisfies CodegenConfig;

What are your thoughts on mentioning this config in the Guide: GraphQL Yoga / Apollo Server with Server Preset guide?

(Thanks for this library btw. I like the conventions it enforces)

zach-betz-hln avatar Jul 31 '25 20:07 zach-betz-hln

Good idea @zach-betz-hln ! I'll add a new section about context type since it's a fairly common question

eddeee888 avatar Aug 03 '25 13:08 eddeee888

@eddeee888 question in this context 😸 ...

For typescript projects of type: module, when defining the context, can we configure exports to append the output filetype as .js?

Right now I'm achieving this using the following config:

const config: CodegenConfig = {
  schema: 'src/**/schema.graphql',
  generates: {
    'src/gql-gen': defineConfig({
      add: {
        './types.generated.ts': {
          content: "import { MyContext } from '../types/MyContext.js'",
        },
      },
      emitLegacyCommonJSImports: false,
      typesPluginsConfig: {
        federation: true,
        contextType: 'MyContext',
      },
    }),
  },
};

This totally works, but just took me a while to work out. If this is the way this needs to be done, should an example of this be added to docs/examples?

Is there a better way to do this?

LongLiveCHIEF avatar Sep 03 '25 17:09 LongLiveCHIEF

Hello @LongLiveCHIEF ! Thanks for sharing your solution!

contextType could be used to declare the type extension if you prefer e.g.

const config: CodegenConfig = {
  schema: 'src/**/schema.graphql',
  generates: {
    'src/gql-gen': defineConfig({
      emitLegacyCommonJSImports: false,
      typesPluginsConfig: {
        federation: true,
        contextType: 'path-to/MyContext.js#MyContext',
      },
    }),
  },
};

eddeee888 avatar Sep 05 '25 11:09 eddeee888

Hi @LongLiveCHIEF I think this line is key, which emits imports with a .js ext:

emitLegacyCommonJSImports: false

For our projects that have:

  • "type": "module" in package.json
  • "moduleResolution": "node16" in tsconfig.json

Then though it is a TS project, imports must end with a .js ext. More info here on why.

zach-betz-hln avatar Sep 05 '25 17:09 zach-betz-hln