Guide: React and GraphQL
GraphQL Code Generator provides typed code generation for React Query, URQL React, React Apollo Client, and other clients.
The plugins and available options vary depending on the target client; for this reason, you find guides for each of them below:
All the following guides query the schema below:
type Author {
id: Int!
firstName: String!
lastName: String!
posts(findTitle: String): [Post]
}
type Post {
id: Int!
title: String!
author: Author
}
type Query {
posts: [Post]
}React Query
Most React Query usage with GraphQL and TypeScript will look as follows:
import { useQuery } from '@tanstack/react-query'
import { request, gql } from 'graphql-request'
interface PostQuery {
posts: {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}[]
}
const postsQueryDocument = gql`
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const Posts = () => {
const { data } = useQuery<PostQuery>('posts', async () => {
const { posts } = await request(endpoint, postsQueryDocument)
return posts
})
// …
}Not typing or manually maintaining the data-types can lead to many issues:
-
outdated typing (regarding the current Schema)
-
typos
-
partial typing of data (not all Schema's fields has a corresponding type)
For this reason, GraphQL Code Generator provides a @graphql-codegen/typescript-react-query plugin that generates a typed hook for each GraphQL operation.
Just a few configuration steps are required to get those typed hooks generated:
1. Install the @graphql-codegen/typescript-react-query plugin
yarn add -D @graphql-codegen/typescript-react-query @graphql-codegen/typescript @graphql-codegen/typescript-operations2. Configure the plugin
Create or update your codegen.yaml file as follows:
schema: http://my-graphql-api.com/graphql
documents: './src/**/*.tsx'
generates:
./graphql/generated.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-query
config:
fetcher: fetchschema and documents values
schema needs to be your target GraphQL API URL ("/graphql" included).
documents is a glob expression to your .graphql, .ts or .tsx files.
3. Run the codegen and update your code
Assuming that, as recommended, your package.json has the following script:
{
"scripts": {
"generate": "graphql-codegen"
}
}Running the following will generate the graphql/generated.tsx file.
yarn generateWe can now update our code as follows:
import gql from 'graphql-tag'
import { useQuery } from '@tanstack/react-query'
import { usePosts } from '../graphql/generated'
gql`
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const Posts = () => {
const { data } = usePosts()
// `data` is typed!
// …
}For more advanced configuration (custom fetcher, infinite queries), please refer to the plugin documentation.
For a different organization of the generated files, please refer to the "Generated files colocation" page.
Apollo and URQL
Optimal configuration for Apollo and URQL
While Apollo and URQL have their GraphQL Code Generator plugins that generate fully-typed hooks, they are also compatible with a plugin named @graphql-codegen/typed-document-node.
@graphql-codegen/typed-document-node plugin provides the best Developer Experience for Apollo and URQL:
- low bundle impact (compared to other plugins)
- better backward compatibility (easier to migrate to)
- more flexible
Given the following code example:
import { gql, useQuery } from '@apollo/client'
interface PostQuery {
posts: {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}[]
}
const postsQueryDocument = gql`
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const Posts = () => {
const { data } = useQuery<PostQuery>(postsQueryDocument)
// …
}installing and configuring the @graphql-codegen/typed-document-node plugin would allow the following refactoring:
import { useQuery } from '@apollo/client'
import { postsQueryDocument } from './graphql/generated'
const Posts = () => {
const { data } = useQuery(postsQueryDocument)
// `result` is fully typed!
// …
}Just a few configuration steps are required to get those typed document nodes generated:
1. Move all your GraphQL documents in dedicated .graphql files
To have @graphql-codegen/typed-document-node working and avoid code duplication,
we highly recommend moving all gql document declarations outside of .tsx/.ts files.
For this, create a colocated .graphql file for each GraphQL document, as follows:
# 'Document' will be appended to the name of the query in the generated output
query postsQuery {
posts {
id
title
author {
id
firstName
lastName
}
}
}2. Install the @graphql-codegen/typed-document-node plugin
yarn add -D @graphql-codegen/typed-document-node @graphql-codegen/typescript @graphql-codegen/typescript-operations3. Configure the plugin
Create or update your codegen.yaml file as follows:
schema: http://my-graphql-api.com/graphql
documents: './src/**/*.graphql'
generates:
./src/generated.ts:
plugins:
- typescript
- typescript-operations
- typed-document-nodeschema and documents values
schema needs to be your target GraphQL API URL ("/graphql" included).
documents is a glob expression to your .graphql files.
4. Run the codegen and update your code
Assuming that, as recommended, your package.json has the following script:
{
"scripts": {
"generate": "graphql-codegen"
}
}Running the following generates the graphql/generated.tsx file.
yarn generateWe can now update our code as follows:
import { useQuery } from '@apollo/client'
import { postsQueryDocument } from './graphql/generated'
const Posts = () => {
const { data } = useQuery<PostQuery>(postsQueryDocument)
// `result` is fully typed!
// …
}For more advanced configuration, please refer to the plugin documentation.
If you are curious about @graphql-codegen/typed-document-node inner workings, feel free to read the following The Guild's CTO blog post: TypedDocumentNode: the next generation of GraphQL and TypeScript.
Typed hooks for Apollo and URQL
GraphQL Code Generator also proposes two plugins (one for Apollo one for URQL) that generate fully-typed hooks.
Given the following code example:
import { gql, useQuery } from '@apollo/client'
interface PostQuery {
posts: {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}[]
}
const postsQueryDocument = gql`
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const Posts = () => {
const { data } = useQuery<PostQuery>(postsQueryDocument)
// …
}installing and configuring the @graphql-codegen/typescript-react-apollo or @graphql-codegen/typescript-urql plugin would allow the following refactoring:
import { usePostsQuery } from './graphql/generated'
const Posts = () => {
const { data } = usePostsQuery()
// `result` is fully typed!
// …
}Some might prefer this approach to @graphql-codegen/typed-document-node since its results in a total abstraction of the query logic and fewer imports.
However, keep in mind that hooks generation results in:
- greater bundle size
- an increase of the number of specific hooks in the given application
Just a few configuration steps are required to get those typed hooks generated:
1. Install the @graphql-codegen/typescript-react-apollo or @graphql-codegen/typescript-urql plugin
For React Apollo:
yarn add -D @graphql-codegen/typescript-react-apollo @graphql-codegen/typescript @graphql-codegen/typescript-operationsFor URQL React:
yarn add -D @graphql-codegen/typescript-urql @graphql-codegen/typescript @graphql-codegen/typescript-operations2. Configure the plugin
Create or update your codegen.yaml file as follows:
schema: http://my-graphql-api.com/graphql
documents: './src/**/*.tsx'
generates:
graphql/generated.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
config:
withHooks: trueschema and documents values
schema needs to be your target GraphQL API URL ("/graphql" included).
documents is a glob expression to your .graphql, .ts or .tsx files.
3. Run the codegen and update your code
Assuming that, as recommended, your package.json has the following script:
{
"scripts": {
"generate": "graphql-codegen"
}
}Running the following generates the graphql/generated.tsx file.
yarn generateWe can now update our code as follows:
import { usePostsQuery } from './graphql/generated'
const Posts = () => {
const { data } = usePostsQuery()
// `result` is fully typed!
// …
}For more advanced configuration, please refer to the plugin documentation:
@graphql-codegen/typescript-react-apollodocumentation@graphql-codegen/typescript-urqldocumentation
For a different organization of the generated files, please refer to the "Generated files colocation" page.