Automating GraphQL Code Generation in React Query (NextJS)
JP Calvo
Posted on July 11, 2023
When working with GraphQL APIs, developers often encounter repetitive tasks such as writing boilerplate code for queries, mutations, and types. Manually managing these tasks not only consumes valuable development time but also increases the risk of introducing errors and inconsistencies.
To address this challenge, we can leverage the power of GraphQL Codegen along with React Query to automate code generation and streamline the integration between GraphQL and React applications. In this article, we will explore how to set up and use GraphQL Codegen with React Query in a Next.js project to automate the generation of hooks and types based on your GraphQL schema.
The Problem: Manual Code Generation
Developers working with GraphQL APIs often find themselves in a situation where they need to manually write repetitive code for queries, mutations, and types. This manual process is time-consuming, error-prone, and can lead to inconsistencies between the frontend and backend codebases. It becomes increasingly challenging to keep the frontend code in sync with the server schema as the project grows in complexity.
The Solution: GraphQL Codegen and React Query
To automate code generation and eliminate the manual effort involved in creating GraphQL-related code, we can utilize a powerful tool called GraphQL Codegen. GraphQL Codegen allows us to automatically generate TypeScript types, hooks, and other utilities based on our GraphQL schema.
When combined with React Query, a popular data-fetching library for React applications, we can further enhance our development workflow. React Query simplifies data fetching, caching, and state management, providing a seamless integration with GraphQL Codegen-generated code. This combination ensures type safety, improves developer productivity, and reduces the likelihood of errors.
In the following sections, we will walk through the installation process, configuration setup, and demonstrate how to generate code based on our GraphQL schema. By the end of this article, you will have a clear understanding of how to harness the power of GraphQL Codegen and React Query to automate code generation and improve your GraphQL development experience.
Prerequisites
Before we begin, make sure you have the following installed on your system:
- node.js (version 14 or higher)
- a package manager like npm
Installation
To get started, we need to set up a new Next.js project. Open your terminal and run the following command:
npx create-next-app@latest myapp --use-npm --ts
This command will scaffold a new Next.js project using npm as the package manager. Feel free to replace myapp
with the desired name of your project.
Once the project is created, navigate to the project directory:
cd myapp
Now, let's install the required dependencies:
npm install @tanstack/react-query graphql graphql-request
Next, we need to install the following packages as dev dependencies:
npm install --save-dev dotenv graphql-config @graphql-codegen/cli @graphql-codegen/add @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-query
Configuring GraphQL Codegen
First, we need to create a .env file at the root of our project and define the API URL. For demonstration purposes, we will use the countries API. Open the .env file and add the following line:
NEXT_PUBLIC_COUNTRIES_API=https://countries.trevorblades.com/
Next, let's create a configuration file for GraphQL Codegen. Create a new file named .graphql.ts at the root of your project. Note that we are deviating from the recommended codegen.yml naming convention to enable integration with the VSCode extension, which supports specific file name formats such as .graphql.ts. This enables autocompletion and provides a more enhanced development experience.
Inside the .graphql.ts
file, paste the following code:
import dotenv from "dotenv";
import { IGraphQLConfig } from "graphql-config";
dotenv.config({
debug: true,
path: ".env",
});
const config: IGraphQLConfig = {
schema: [process.env.NEXT_PUBLIC_COUNTRIES_API!],
documents: ["src/graphql/**/*.gql"],
extensions: {
codegen: {
debug: true,
verbose: true,
ignoreNoDocuments: true,
overwrite: true,
hooks: {
afterAllFileWrite: ["prettier --write"],
},
generates: {
"src/__generated__/index.ts": {
plugins: [
"typescript",
"typescript-operations",
"typescript-react-query",
{
add: {
content: "/* eslint-disable */\n// @ts-nocheck\n",
},
},
],
config: {
addDocBlocks: false,
dedupeFragments: true,
pureMagicComment: true,
disableDescriptions: true,
fetcher: "graphql-request",
legacyMode: false,
exposeFetcher: true,
exposeDocument: true,
exposeQueryKeys: true,
exposeMutationKeys: true,
addInfiniteQuery: true,
errorType: "any",
},
},
},
},
},
};
export default config;
This configuration file specifies the schema location, document paths, code generation options, and output file paths. It also defines the plugins to be used, such as TypeScript, TypeScript Operations, and TypeScript React Query.
Integrating React Query and GraphQL Request
Let's create our config file first. Create a file named config.ts
just under src/app
and add the following lines:
import { QueryClient } from "@tanstack/react-query";
import { GraphQLClient } from "graphql-request";
export const queryClient = new QueryClient();
export const graphqlClient = new GraphQLClient(
process.env.NEXT_PUBLIC_COUNTRIES_API as string,
);
Now, create a file called AppProvider.tsx
in src/app
directory and paste the following code into the file:
"use client";
import { QueryClientProvider } from "@tanstack/react-query";
import { PropsWithChildren } from "react";
import { queryClient } from "./config";
export function AppProvider({ children }: PropsWithChildren) {
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
}
Next, open the src/app/layout.tsx file and replace its contents with the following code:
import { Metadata } from "next";
import { Inter } from "next/font/google";
import { PropsWithChildren } from "react";
import { AppProvider } from "./AppProvider";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({ children }: PropsWithChildren) {
return (
<html lang="en">
<body className={inter.className}>
<AppProvider>{children}</AppProvider>
</body>
</html>
);
}
Creating GraphQL Queries/Mutations and Generating Code with GraphQL Codegen
To demonstrate how to create GraphQL queries and mutations, let's start by creating a basic query. Inside the src/graphql
directory, create a file named queries.gql
and paste the following code:
query Countries($filter: CountryFilterInput) {
countries(filter: $filter) {
code
name
}
}
You should get autocompletion in VSCode, if not, please restart your editor.
Now, the last step is to run the command below to generate our hooks and types:
graphql-codegen --config .graphql.ts
If the operation is successful, you should see a new file named index.ts
inside the src/__generated__
directory. This file contains all the generated types and hooks, ready to be imported and used in your components.
Here's an example of how you can use the generated hook:
// src/app/Countries.tsx
"use client";
import { useCountriesQuery } from "@/__generated__";
import { graphqlClient } from "./config";
export function Countries() {
const { data, isLoading } = useCountriesQuery(graphqlClient, {
filter: {
code: {
eq: "PH",
},
},
});
return (
<div>
{isLoading && <p>Loading...</p>}
<ul>
{data?.countries.map(({ code, name }) => (
<li key={code}>{name}</li>
))}
</ul>
</div>
);
}
To access query keys, you can use the useCountriesQuery.getKey
function like so
useCountriesQuery.document;
If you want to prefetch queries for example in getStaticProps
, you can use the following example:
import { CountryFilterInput, useCountriesQuery } from "@/__generated__";
import { graphqlClient, queryClient } from "./config";
export async function getStaticProps() {
const filter: CountryFilterInput = {
code: {
eq: "PH",
},
};
await queryClient.prefetchQuery({
queryKey: useCountriesQuery.getKey({ filter }),
queryFn() {
return useCountriesQuery.fetcher(graphqlClient, { filter });
},
});
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
}
These updates demonstrate how to use the generated hook, access query keys and the document node, and prefetch queries using getStaticProps
in Next.js.
Let me know if there's anything else I can help you with!
Conclusion
In this article, we explored the process of automating GraphQL code generation with React Query in a Next.js project. By using GraphQL Codegen, we can automatically generate TypeScript types and hooks based on our GraphQL schema. The integration with React Query simplifies data fetching and state management, improving development efficiency and reducing the likelihood of errors.
By following the installation steps, configuring GraphQL Codegen, and leveraging React Query, you can streamline your GraphQL development workflow and enhance your productivity. Feel free to experiment with different queries, mutations, and code generation options to suit your project's needs.
Happy coding!
References
- VSCode GraphQL Extension: A Visual Studio Code extension that provides GraphQL syntax highlighting, autocomplete, and other helpful features.
- GraphQL Codegen: A tool that generates code based on your GraphQL schema and queries, reducing the amount of manual work required.
- React Query: A powerful data-fetching library for React applications that simplifies API fetching, caching, and state management.
- Next.js: A popular React framework for building server-rendered and statically generated web applications.
- GraphQL: A query language for APIs that provides a flexible and efficient approach to data fetching and manipulation.
Posted on July 11, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.