-
Notifications
You must be signed in to change notification settings - Fork 2k
docs: type generation for graphql servers #4376
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
base: 16.x.x
Are you sure you want to change the base?
Conversation
Hi @sarahxsanders, I'm @github-actions bot happy to help you with this PR 👋 Supported commandsPlease post this commands in separate comments and only one per comment:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @sarahxsanders !
I'm from the GraphQL Codegen team at The Guild. I've left some minor comments about our recommendation when using Codegen. Keen to hear your thoughts!
I've fixed CI after rebasing this branch it will work again, apologies for the issues |
Hi @sarahxsanders , thanks for making the changes to recommend presets. |
@eddeee888 you are absolutely welcome to write those sections! happy to collab if you want a review or anything |
Thank you @sarahxsanders ! I'll draft something up this week, and let you know |
}, | ||
}; | ||
export default config; | ||
``` | ||
|
||
To run the generator: | ||
|
||
```bash | ||
npx graphql-codegen | ||
``` | ||
|
||
This creates a set of resolver types like: | ||
|
||
```ts | ||
export type QueryResolvers<ContextType = any> = { | ||
user?: Resolver<User, any, ContextType, RequireFields<QueryUserArgs, 'id'>>; | ||
}; | ||
``` | ||
|
||
These types ensure that the `user` resolver expects an `id` argument and returns a | ||
`User`, giving you confidence and autocomplete while implementing your server logic. | ||
|
||
## Using generated types in your server | ||
|
||
Once generated, you can use these types directly in your resolver map: | ||
|
||
```ts | ||
import { QueryResolvers } from './generated/resolvers-types'; | ||
|
||
export const queryResolvers: QueryResolvers = { | ||
user: (parent, args, context) => { | ||
return context.db.getUser(args.id); | ||
}, | ||
}; | ||
``` | ||
|
||
You can also extract shared `ContextType` and `Resolver` | ||
utility types from the generated file and apply them across your codebase. | ||
|
||
## Generating operation types | ||
|
||
In addition to resolver types, you can generate types for GraphQL operations such | ||
as queries, mutations, and fragments. This is especially useful for shared integration tests | ||
or client logic that needs to match the schema precisely. | ||
|
||
We recommend using the GraphQL Code Generator Server Preset for generating operation types. | ||
The server preset generates both resolver and operation types, without needing to install | ||
or configure additional plugins. | ||
|
||
Suppose you have a query in `./src/operations/getUser.graphql`: | ||
|
||
```graphql | ||
query GetUser($id: ID!) { | ||
user(id: $id) { | ||
id | ||
name | ||
} | ||
} | ||
``` | ||
|
||
Update your codegen config: | ||
|
||
```ts | ||
import type { CodegenConfig } from '@graphql-codegen/cli'; | ||
|
||
const config: CodegenConfig = { | ||
schema: './schema.graphql', | ||
documents: './src/operations/**/*.graphql', | ||
generates: { | ||
'./src/generated/': { | ||
preset: 'graphql-codegen-preset-server', | ||
}, | ||
}, | ||
}; | ||
export default config; | ||
``` | ||
|
||
This produces types like `GetUserQuery` and `GetUserQueryVariables`, which you can | ||
import into your client code or test files. | ||
|
||
## Typing resolvers manually | ||
|
||
If you aren't ready to introduce type generation, you can still get partial type safety | ||
using `graphql-js` built-in types. | ||
|
||
```ts | ||
import { GraphQLFieldResolver } from 'graphql'; | ||
|
||
const myResolver: GraphQLFieldResolver<MyParent, MyContext> = ( | ||
parent, | ||
args, | ||
context, | ||
info | ||
) => { | ||
// ... | ||
}; | ||
``` | ||
|
||
This pattern may be enough for small projects or static schemas, but it | ||
can be hard to maintain and scale without automation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With a schema-first workflow, you can: | |
- Generate resolver type definitions that match your schema | |
- Generate operation types for client queries, integration tests, or internal tooling | |
- Detect breaking changes and unused types through schema diffing tools | |
## Generating resolver types | |
We recommend using the [GraphQL Code Generator Server Preset](https://the-guild.dev/graphql/codegen/docs/guides/graphql-server-apollo-yoga-with-server-preset) | |
to generate resolver types. It automatically generates resolver types based on your schema, including parent types, | |
arguments, return values, and context, without needing extra plugin setup. | |
Example `codegen.ts` config: | |
```ts | |
import type { CodegenConfig } from '@graphql-codegen/cli'; | |
const config: CodegenConfig = { | |
schema: './schema.graphql', | |
generates: { | |
'./src/generated/resolvers-types.ts': { | |
plugins: ['typescript', 'typescript-resolvers'], | |
}, | |
}, | |
}; | |
export default config; | |
``` | |
To run the generator: | |
```bash | |
npx graphql-codegen | |
``` | |
This creates a set of resolver types like: | |
```ts | |
export type QueryResolvers<ContextType = any> = { | |
user?: Resolver<User, any, ContextType, RequireFields<QueryUserArgs, 'id'>>; | |
}; | |
``` | |
These types ensure that the `user` resolver expects an `id` argument and returns a | |
`User`, giving you confidence and autocomplete while implementing your server logic. | |
## Using generated types in your server | |
Once generated, you can use these types directly in your resolver map: | |
```ts | |
import { QueryResolvers } from './generated/resolvers-types'; | |
export const queryResolvers: QueryResolvers = { | |
user: (parent, args, context) => { | |
return context.db.getUser(args.id); | |
}, | |
}; | |
``` | |
You can also extract shared `ContextType` and `Resolver` | |
utility types from the generated file and apply them across your codebase. | |
## Generating operation types | |
In addition to resolver types, you can generate types for GraphQL operations such | |
as queries, mutations, and fragments. This is especially useful for shared integration tests | |
or client logic that needs to match the schema precisely. | |
We recommend using the GraphQL Code Generator Server Preset for generating operation types. | |
The server preset generates both resolver and operation types, without needing to install | |
or configure additional plugins. | |
Suppose you have a query in `./src/operations/getUser.graphql`: | |
```graphql | |
query GetUser($id: ID!) { | |
user(id: $id) { | |
id | |
name | |
} | |
} | |
``` | |
Update your codegen config: | |
```ts | |
import type { CodegenConfig } from '@graphql-codegen/cli'; | |
const config: CodegenConfig = { | |
schema: './schema.graphql', | |
documents: './src/operations/**/*.graphql', | |
generates: { | |
'./src/generated/': { | |
preset: 'graphql-codegen-preset-server', | |
}, | |
}, | |
}; | |
export default config; | |
``` | |
This produces types like `GetUserQuery` and `GetUserQueryVariables`, which you can | |
import into your client code or test files. | |
## Typing resolvers manually | |
If you aren't ready to introduce type generation, you can still get partial type safety | |
using `graphql-js` built-in types. | |
```ts | |
import { GraphQLFieldResolver } from 'graphql'; | |
const myResolver: GraphQLFieldResolver<MyParent, MyContext> = ( | |
parent, | |
args, | |
context, | |
info | |
) => { | |
// ... | |
}; | |
``` | |
This pattern may be enough for small projects or static schemas, but it | |
can be hard to maintain and scale without automation. | |
With a schema-first workflow, you can: | |
- Generate resolver type definitions and files that match your schema | |
- Generate operation types for client queries, integration tests, or internal tooling | |
- Detect breaking changes and unused types through schema diffing tools | |
## Generating resolver types | |
We recommend using the [Server Preset](https://www.npmjs.com/package/@eddeee888/gcg-typescript-resolver-files) for a managed workflow. It automatically generates types and files based on your schema without needing extra plugin setup: | |
- resolver types, including parent types, arguments, return values, and context. | |
- resolver files with types wired up, ready for your business logic | |
- resolver map and type definitions to plug into GraphQL servers | |
Example codegen config: | |
```ts filename="codegen.ts" | |
import type { CodegenConfig } from "@graphql-codegen/cli"; | |
import { defineConfig } from "@eddeee888/gcg-typescript-resolver-files"; | |
const config: CodegenConfig = { | |
schema: "src/**/schema.graphql", | |
generates: { | |
"src/schema": defineConfig({ | |
resolverGeneration: "minimal", | |
}), | |
}, | |
}; | |
export default config; |
Note: this setup expects your schema is split into modules to improve readability and maintainability:
├── src/
│ ├── schema/
│ │ ├── base/
│ │ │ ├── schema.graphql
│ │ ├── user/
│ │ │ ├── schema.graphql
│ │ ├── book/
│ │ │ ├── schema.graphql
To run the generator:
npx graphql-codegen
This creates resolver files that like:
import type { QueryResolvers } from "./../../../types.generated";
export const user: NonNullable<QueryResolvers["user"]> = async (
_parent,
_arg,
_ctx,
) => {
/* Implement Query.user resolver logic here */
};
The user query resolver is typed to ensure that the user
resolver expects an id
argument and returns a
User
, giving you confidence and autocomplete while implementing your server logic, which may look like this:
export const user: NonNullable<QueryResolvers["user"]> = async (
parent,
args,
context,
) => {
return context.db.getUser(args.id);
};
Check out the official Server Preset guide to learn about its other features, including mappers convention and static analysis for runtime safety.
Generating operation types
In addition to resolver types, you can generate types for GraphQL operations such as queries, mutations, and fragments. This is especially useful for shared integration tests or client logic that needs to match the schema precisely.
We recommend using the GraphQL Code Generator Client Preset for a managed workflow:
- write operations with GraphQL syntax in the same file where it is used
- get type-safety when using the result
Example codegen config
import type { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {
schema: "src/**/schema.graphql",
documents: ["src/**/*.ts"],
ignoreNoDocuments: true,
generates: {
"./src/graphql/": {
preset: "client",
config: {
documentMode: "string",
},
},
},
};
export default config;
Now, run codegen in watch mode:
npx graphql-codegen --config codegen.ts --watch
Now, we can import the graphql
function from src/graphql/
to write GraphQL operations directly in your TypeScript files:
import { graphql } from "./graphql";
const UserQuery = graphql(`
query User($id: ID!) {
user(id: ID!) {
id
fullName
}
}
`);
const response = await fetch("https://graphql.org/graphql/", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/graphql-response+json",
},
body: JSON.stringify({
query: UserQuery,
variables: { id: "1" },
}),
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
const result: ResultOf<typeof UserQuery> = await response.json();
console.log(result);
Check out Client Preset guides for popular framework and GraphQL clients:
Hi @sarahxsanders, I've left a draft here: https://github.com/graphql/graphql-js/pull/4376/files#r2091097002 |
Adds new guide: Type Generation for GraphQL Servers
This is a part of the effort to expand GraphQL.js documentation