GraphQL
Code Generation
Code Generation
Automate the generation of TypeScript types, React hooks, and resolvers from your GraphQL schema and operations using GraphQL Code Generator.
GraphQL Code Generator
Install and configure GraphQL Code Generator:
# Install dependencies
npm install -D @graphql-codegen/cli \
@graphql-codegen/typescript \
@graphql-codegen/typescript-operations \
@graphql-codegen/typescript-react-apollo
# Initialize configuration
npx graphql-codegen init
# Or create codegen.yml manually
# codegen.yml
schema: http://localhost:4000/graphql
documents: 'src/**/*.graphql'
generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
config:
withHooks: true
withComponent: false
withHOC: false
Generating TypeScript Types
Generate type-safe TypeScript definitions from your schema:
# schema.graphql
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
type Query {
user(id: ID!): User
users: [User!]!
}
type Mutation {
createUser(input: CreateUserInput!): User!
}
input CreateUserInput {
name: String!
email: String!
}
# Run code generation
npm run codegen
# Generated types in src/generated/graphql.ts
export type User = {
__typename?: 'User';
id: Scalars['ID'];
name: Scalars['String'];
email: Scalars['String'];
posts: Array<Post>;
};
export type Post = {
__typename?: 'Post';
id: Scalars['ID'];
title: Scalars['String'];
content: Scalars['String'];
author: User;
};
export type CreateUserInput = {
name: Scalars['String'];
email: Scalars['String'];
};
Note: Generated types automatically include
__typename fields for GraphQL type identification and caching.
Generating React Hooks
Create type-safe React hooks from your GraphQL operations:
# src/graphql/queries.graphql
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
posts {
id
title
}
}
}
query GetUsers {
users {
id
name
email
}
}
# src/graphql/mutations.graphql
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
// Generated hooks in src/generated/graphql.ts
export function useGetUserQuery(
baseOptions: Apollo.QueryHookOptions<GetUserQuery, GetUserQueryVariables>
) {
return Apollo.useQuery<GetUserQuery, GetUserQueryVariables>(
GetUserDocument,
baseOptions
);
}
export function useCreateUserMutation(
baseOptions?: Apollo.MutationHookOptions<
CreateUserMutation,
CreateUserMutationVariables
>
) {
return Apollo.useMutation<CreateUserMutation, CreateUserMutationVariables>(
CreateUserDocument,
baseOptions
);
}
// Usage in React component
import { useGetUserQuery, useCreateUserMutation } from './generated/graphql';
function UserProfile({ userId }: { userId: string }) {
const { data, loading, error } = useGetUserQuery({
variables: { id: userId },
});
const [createUser] = useCreateUserMutation();
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h1>{data?.user?.name}</h1>
<p>{data?.user?.email}</p>
</div>
);
}
Tip: Use the
--watch flag with codegen to automatically regenerate types when GraphQL files change: npm run codegen -- --watch
Generating Resolvers
Generate type-safe resolver signatures for your server:
# codegen.yml for server-side
schema: ./schema.graphql
generates:
src/generated/resolvers.ts:
plugins:
- typescript
- typescript-resolvers
config:
useIndexSignature: true
contextType: ./context#Context
mappers:
User: ./models#UserModel
Post: ./models#PostModel
// Generated resolver types
import { GraphQLResolveInfo } from 'graphql';
import { UserModel, PostModel } from './models';
import { Context } from './context';
export type Resolvers<ContextType = Context> = {
Query?: QueryResolvers<ContextType>;
Mutation?: MutationResolvers<ContextType>;
User?: UserResolvers<ContextType>;
Post?: PostResolvers<ContextType>;
};
export type QueryResolvers<ContextType = Context> = {
user?: Resolver<Maybe<User>, {}, ContextType, RequireFields<QueryUserArgs, 'id'>>;
users?: Resolver<Array<User>, {}, ContextType>;
};
export type MutationResolvers<ContextType = Context> = {
createUser?: Resolver<User, {}, ContextType, RequireFields<MutationCreateUserArgs, 'input'>>;
};
// Use generated types in your resolvers
import { Resolvers } from './generated/resolvers';
export const resolvers: Resolvers = {
Query: {
user: async (_, { id }, { db }) => {
return db.user.findUnique({ where: { id } });
},
users: async (_, __, { db }) => {
return db.user.findMany();
},
},
Mutation: {
createUser: async (_, { input }, { db }) => {
return db.user.create({ data: input });
},
},
};
Codegen Configuration
Advanced configuration options for different use cases:
# codegen.yml - Full configuration example
schema: http://localhost:4000/graphql
documents:
- 'src/**/*.graphql'
- 'src/**/*.tsx'
generates:
# Client-side types and hooks
src/generated/client.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
config:
withHooks: true
withComponent: false
withHOC: false
skipTypename: false
enumsAsTypes: true
constEnums: true
# Server-side resolver types
src/generated/server.ts:
plugins:
- typescript
- typescript-resolvers
config:
useIndexSignature: true
contextType: ../context#Context
defaultMapper: Partial<{T}>
mappers:
User: ../models#UserModel
Post: ../models#PostModel
# GraphQL schema as TypeScript
src/generated/schema.ts:
plugins:
- typescript
- typescript-graphql-files-modules
# Introspection result
src/generated/introspection.json:
plugins:
- introspection
hooks:
afterAllFileWrite:
- prettier --write
- eslint --fix
CI/CD Integration
Integrate code generation into your build pipeline:
{
"scripts": {
"codegen": "graphql-codegen --config codegen.yml",
"codegen:watch": "graphql-codegen --config codegen.yml --watch",
"prebuild": "npm run codegen",
"build": "tsc",
"pretest": "npm run codegen",
"test": "jest"
}
}
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Generate GraphQL types
run: npm run codegen
- name: Run type check
run: npm run type-check
- name: Run tests
run: npm test
- name: Build
run: npm run build
Warning: Always commit generated files to version control or regenerate them in CI/CD. Document your choice in your project README.
Exercise:
- Set up GraphQL Code Generator with both client and server configurations
- Create GraphQL operations in
.graphqlfiles - Generate TypeScript types, React hooks, and resolver types
- Build a React component using generated hooks
- Implement server resolvers using generated types
- Add codegen to your build pipeline and test it