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:
# schema.graphql
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 '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 @graphql-codegen/typescript-react-query
yarn add @graphql-codegen/typescript
yarn add @graphql-codegen/typescript-operations
pnpm add @graphql-codegen/typescript-react-query
pnpm add @graphql-codegen/typescript
pnpm add @graphql-codegen/typescript-operations
npm install @graphql-codegen/typescript-react-query
npm install @graphql-codegen/typescript
npm install @graphql-codegen/typescript-operations
2. 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: fetch
schema
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 generate
pnpm generate
npm run generate
We can now update our code as follows:
import gql from 'graphql-tag'
import { useQuery } from '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)
// ...
}
import { useQuery } from 'urql'
interface PostQuery {
posts: {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}[]
}
const postsQueryDocument = `
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const Posts = () => {
const [result] = useQuery<PostQuery>({ query: 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!
// ...
}
import { useQuery } from 'urql'
import { postsQueryDocument } from './graphql/generated'
const Posts = () => {
const [result] = useQuery({ query: 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:
# postsQuery.graphql
# '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 @graphql-codegen/typed-document-node
yarn add @graphql-codegen/typescript
yarn add @graphql-codegen/typescript-operations
pnpm add @graphql-codegen/typed-document-node
pnpm add @graphql-codegen/typescript
pnpm add @graphql-codegen/typescript-operations
npm install @graphql-codegen/typed-document-node
npm install @graphql-codegen/typescript
npm install @graphql-codegen/typescript-operations
3. 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-node
schema
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 generate
pnpm generate
npm run generate
We 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!
// ...
}
import { useQuery } from 'urql'
import { postsQueryDocument } from './graphql/generated'
const Posts = () => {
const [result] = useQuery<PostQuery>({ query: 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)
// ...
}
import { useQuery } from 'urql'
interface PostQuery {
posts: {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}[]
}
const postsQueryDocument = `
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const Posts = () => {
const [result] = useQuery<PostQuery>({ query: 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!
// ...
}
import { usePostsQuery } from './graphql/generated'
const Posts = () => {
const [result] = 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 @graphql-codegen/typescript-react-apollo
yarn add @graphql-codegen/typescript
yarn add @graphql-codegen/typescript-operations
pnpm add @graphql-codegen/typescript-react-apollo
pnpm add @graphql-codegen/typescript
pnpm add @graphql-codegen/typescript-operations
npm install @graphql-codegen/typescript-react-apollo
npm install @graphql-codegen/typescript
npm install @graphql-codegen/typescript-operations
For URQL React:
yarn add @graphql-codegen/typescript-urql
yarn add @graphql-codegen/typescript
yarn add @graphql-codegen/typescript-operations
pnpm add @graphql-codegen/typescript-urql
pnpm add @graphql-codegen/typescript
pnpm add @graphql-codegen/typescript-operations
npm install @graphql-codegen/typescript-urql
npm install @graphql-codegen/typescript
npm install @graphql-codegen/typescript-operations
2. 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: true
schema: http://my-graphql-api.com/graphql
documents: './src/**/*.tsx'
generates:
graphql/generated.ts:
plugins:
- typescript
- typescript-operations
- typescript-urql
config:
withHooks: true
schema
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 generate
pnpm generate
npm run generate
We can now update our code as follows:
import { usePostsQuery } from './graphql/generated'
const Posts = () => {
const { data } = usePostsQuery()
// `result` is fully typed!
// ...
}
import { usePostsQuery } from './graphql/generated'
const Posts = () => {
const [result] = usePostsQuery()
// `result` is fully typed!
// ...
}
For more advanced configuration, please refer to the plugin documentation:
@graphql-codegen/typescript-react-apollo
documentation@graphql-codegen/typescript-urql
documentation
For a different organization of the generated files, please refer to the "Generated files colocation" page.