Automating GraphQL Code Generation in React Query (NextJS)
Tags: graphql, react, typescript, productivity
Published: 2023-07-11 04:08:25

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:

```bash
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:

```bash
cd myapp
```

Now, let's install the required dependencies:

```bash
npm install @tanstack/react-query graphql graphql-request
```

Next, we need to install the following packages as dev dependencies:

```bash
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:

```bash
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:

```ts
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:

```ts
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:

```tsx
"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:

```tsx
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:

```graphql
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:

```bash
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:

```tsx
// 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

```ts
useCountriesQuery.document;
```

If you want to prefetch queries for example in `getStaticProps`, you can use the following example:

```tsx
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](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql): A Visual Studio Code extension that provides GraphQL syntax highlighting, autocomplete, and other helpful features.
- [GraphQL Codegen](https://the-guild.dev/graphql/codegen): A tool that generates code based on your GraphQL schema and queries, reducing the amount of manual work required.
- [React Query](https://tanstack.com/query/v3/): A powerful data-fetching library for React applications that simplifies API fetching, caching, and state management.
- [Next.js](https://nextjs.org/): A popular React framework for building server-rendered and statically generated web applications.
- [GraphQL](https://graphql.org/): A query language for APIs that provides a flexible and efficient approach to data fetching and manipulation.