Back to Graphql Code Generator

typescript-resolvers

website/src/pages/plugins/typescript/typescript-resolvers.mdx

1.17.77.3 KB
Original Source

import { Callout } from '@theguild/components' import { PluginApiDocs, PluginHeader } from '@/components/plugin' import { pluginGetStaticProps } from '@/lib/plugin-get-static-props' export const getStaticProps = pluginGetStaticProps(__filename, { hasOperationsNote: true })

<Callout> This plugin is meant to be used for low-level use cases or as building block for presets.

For building a GraphQL server schema we recommend using the server-preset. </Callout>

<PluginHeader /> <Callout> Watch [Episode #26 of `graphql.wtf`](https://graphql.wtf/episodes/26-type-safe-resolvers-with-graphql-code-generator) for a quick introduction to this plugin and its features: </Callout> <iframe src="https://youtube.com/embed/tHMaNmqPIC4" /> <Callout> [More weekly episodes are available in `graphql.wtf`](https://graphql.wtf/) by [Jamie Barton](https://twitter.com/notrab). </Callout> <PluginApiDocs />

Usage Example

<Callout> **Quick Start with `typescript-resolvers`**

You can find a blog post we wrote about using and customizing this plugin here

</Callout>

Run graphql-codegen as usual, with this new plugin:

ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'schema.json',
  generates: {
    './src/resolvers-types.ts': {
      plugins: ['typescript', 'typescript-resolvers']
    }
  }
}
export default config

Import the types from the generated file and use in the resolver:

ts
import { Resolvers } from './resolvers-types'

export const resolvers: Resolvers = {
  Query: {
    myQuery: (root, args, context) => {}
  }
}

This will make the resolver fully typed and compatible with typescript compiler, including the handler's arguments and return value.

Generated resolvers can be passed directly into graphql-tools makeExecutableSchema function.

Integration with Apollo-Server

By default apollo-server will not work with generated resolvers signature.

If you are using Apollo Server with TypeScript, note that you need to set useIndexSignature: true in your config, in order to add a compatible index signature (more info).

ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  generates: {
    './resolvers-types.ts': {
      config: {
        useIndexSignature: true
      },
      plugins: ['typescript', 'typescript-resolvers']
    }
  }
}
export default config

If you wish to have an easy start, and have the ability to use resolvers chaining without models types, you can also add to your config defaultMapper: Partial<{T}>. This will allow you to return partial types in your resolvers.

Use Your Model Types (mappers)

If you wish to use your custom model types, codegen allow you to use mappers feature to map GraphQL types to your custom model types. You can find an article explaining how to use mappers here.

Here's the basic example of using it:

ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'schema.graphql',
  generates: {
    './resolvers-types.ts': {
      config: {
        contextType: 'models#MyContextType',
        mappers: {
          User: './models#UserModel',
          Profile: './models#UserProfile'
        }
      },
      plugins: ['typescript', 'typescript-resolvers']
    }
  }
}
export default config

Enum Resolvers

Apollo-Server and schemas built with graphql-tools supports creating resolvers for GraphQL enums.

This is helpful because you can have internal values that are different from the public enum values, and you can use the internal values in your resolvers.

Codegen allows you to specify either mappers or enumValues to map enums in your resolvers, and if you are using it for enums, you'll get a resolver signature for the enum resolvers as well.

Usage Example

With the following schema:

graphql
type Query {
  favoriteColor: Color!
}

enum Color {
  RED
  BLUE
}
ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'schema.graphql',
  generates: {
    './resolvers-types.ts': {
      config: {
        enumValues: {
          Color: './enums#ColorsCode'
        }
      },
      plugins: ['typescript', 'typescript-resolvers']
    }
  }
}
export default config
ts
export enum ColorsCode {
  MY_RED = '#FF0000',
  MY_BLUE = '#0000FF'
}
ts
import { Resolvers } from './resolvers-types'
import { ColorsCode } from './enums'

const resolvers: Resolvers = {
  Color: {
    RED: ColorsCode.MY_RED,
    BLUE: ColorsCode.MY_BLUE
  },
  Query: {
    favoriteColor: () => ColorsCode.MY_RED // Now you cn return this, and it will be mapped to your actual GraphQL enum
  }
}

You can also define the same with explicit enum values:

ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'schema.graphql',
  generates: {
    './resolvers-types.ts': {
      config: {
        enumValues: {
          Color: {
            RED: '#FF0000',
            BLUE: '#0000FF'
          }
        }
      },
      plugins: ['typescript', 'typescript-resolvers']
    }
  }
}
export default config

Or, with mappers:

ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'schema.graphql',
  generates: {
    './resolvers-types.ts': {
      config: {
        mappers: {
          Color: './enums#ColorsCode'
        }
      },
      plugins: ['typescript', 'typescript-resolvers']
    }
  }
}
export default config

Defined shared mappers across configurations

In some case, you might want to share some common mappers between many output file configurations.

To do so, you can leverage the YAML references features as follow:

ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const sharedMappers = {
  ID: 'IDType'
}

const config: CodegenConfig = {
  schema: 'schema.graphql',
  documents: 'src/*.ts',
  generates: {
    'resolvers-types-1.ts': {
      plugins: ['typescript', 'typescript-resolvers'],
      config: {
        mappers: {
          ...sharedMappers,
          String: 'StringType'
        }
      }
    },
    'resolvers-types-2.ts': {
      plugins: ['typescript', 'typescript-resolvers'],
      config: {
        mappers: {
          ...sharedMappers,
          String: 'StringType'
        }
      }
    }
  }
}
export default config

The above configuration will provide the ID type mapping to both resolvers-types-1.ts and resolvers-types-2.ts files.

The complete example is available here: codegen-repros/reusable-mappers

You can also achieve a similar reusable mappers configuration by providing a TypeScript or JavaScript file configuration.