person holding green flower bud

Published: Apr 23, 2024

Last Updated: Sep 1, 2024

Sync Smart: Automating Next.js Development with GraphQL Codegen

In the fast-paced world of web development, connecting the frontend to an ever-evolving backend can be a source of frustration. Changes in API properties or the introduction of new ones often require a time-consuming review of updated documentation—especially when dealing with external GraphQL APIs. This is where the power of code-generation tools shines. Codegen acts not only as a time-saver but also as a safeguard, automating the synchronization process and ensuring that your frontend speaks the same language as your backend, seamlessly.

Introduce Codegen

Codegen is a tool that automatically creates code based on your GraphQL schema. It saves time by generating code like type definitions and query builders, tailored to your API, so you can focus on building your app instead of writing repetitive code.

Prerequisites:

  • Basic GraphQL knowledge
  • Basic Next.js knowledge
  • TypeScript installed in your project
  • PNPM as your package manager

Create Nextjs

If you don't have an existing Next.js app, you can create one using the following command:

SH
npx create-next-app@latest --ts --use-np

Upon installation, you'll be prompted to configure your project. Here's a typical setup:

SH
Need to install the following packages:
create-next-app@14.2.1
Ok to proceed? (y)
✔ What is your project named? … codegen-demo
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes

Install the dependencies with:

SH
pnpm install

Start the development server:

SH
pnpm dev

Access your app at http://localhost:3000.

Integrate the GraphQl API

If you already have an existing GraphQL API, you can skip this step.

Before we integrate Codegen, we need an API to test it. Fortunately, there are many free public GraphQL APIs available. In this blog post, we'll use the Countries GraphQL API.

Create a queries.ts file in the /src directory to store all GraphQL queries:

TYPESCRIPT
const gql = (query: string) => query; 

export const GET_ALL_COUNTRIES = gql(`

query GetAllCountries {
    countries {
      name
      emoji
      code
      phone
    }
  }
`
)

To retrieve the countries, add the following code to src/pages/index.tsx:

TSX
import styles from "./page.module.css";
import { GET_ALL_COUNTRIES } from "../queries";

const fetchAllCounties = async () => {
  try {
    const res = await fetch("https://countries.trevorblades.com/graphql", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        query: GET_ALL_COUNTRIES,
      }),
    });
    const { data } = await res.json();
    return data;
  } catch (error) {
    console.error(error);
  }
};

export default async function Home() {
  const { countries } = await fetchAllCounties();
  return (
    <main className={styles.main}>
      <h1 style={{ marginBlock: "3rem", fontSize: "4rem" }}>
        Show All Countries
      </h1>
      <ul className={styles.grid}>
        {countries &&
          countries.length > 0 &&
          countries.map((country) => (
            <li key={country.code} className={styles.card}>
              <h2>{country.name}</h2>
              <span style={{ fontSize: "60px" }}>{country.emoji}</span>
              <p>{country.code}</p>
              <p>{country.phone}</p>
            </li>
          ))}
      </ul>
    </main>
  );
}

Let's analyze the code:

We import styles from /page.module.css for styling. This CSS file is generated by Next.js and uses CSS modules.

We fetch countries directly in the page component without useEffect, thanks to Next.js 14's capability to fetch data at the page level, including server-side rendering.

The Home page component effortlessly handles asynchronous operations using async/await.

The JSX code is straightforward, focusing on rendering the fetched data.

To test the fetch, ensure the local server is running and visit http://localhost:3000 for a comprehensive list of countries.

Integrate Codegen into Nextjs

After fetching the countries, we rendered them on the page. However, without type definitions, it's unclear what data structure the fetch function returns. This ambiguity is where Codegen becomes invaluable.

Install Codegen

SH
pnpm add graphql
pnpm add -D typescript @graphql-codegen/cli

Add Codegen scripts to the package.json

JSON
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "generate": "graphql-codegen",
    "prebuild": "yarn generate",
    "predev": "yarn generate"
  },

Add the Codegen configuration

Create a codegen.ts file at the root level and add the following:

TYPESCRIPT
import { CodegenConfig } from '@graphql-codegen/cli'
 
const config: CodegenConfig = {
    schema: 'https://countries.trevorblades.com/graphql',
    documents: ['./src/queries.ts'],
    generates: {
        './generated/': {
            preset: 'client',
            plugins: [
                'typescript',
                'typescript-operations',
                {
                  add: {
                    content: '// @ts-nocheck',
                  },
                },
              ],
        },
    }
}
 
export default config

After restarting the server, you'll find the generated GraphQL types accessible under graphql/generated/graphql.ts.

Now, update the pages/index.tsx file by incorporating the required types:

TSX
import styles from "./page.module.css";
import { GET_ALL_COUNTRIES } from "../queries";
import { Query } from "../../generated/graphql";

const fetchAllCounties = async (): Promise<Query | undefined> => {
  try {
    const res = await fetch("https://countries.trevorblades.com/graphql", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        query: GET_ALL_COUNTRIES,
      }),
    });
    const { data } = await res.json();
    return data;
  } catch (error) {
    console.error(error);
  }
};

With these adjustments, TypeScript's auto-complete functionality becomes available, ensuring smoother integration of the GraphQL API with the frontend.

We're almost there. One final step remains: adding the /generate folder to the exclude array in the tsconfig.json file. This will instruct TypeScript to ignore this folder during the build process.

JSON
{
  "compilerOptions": {
  // the rest of the options are the same as in the generated tsconfig.json
  },
  "include": ["next-env.d.ts","**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules", "./generated"]
}

Conclusion:

In this blog post, we've explored how code generation can streamline the integration of GraphQL APIs with Next.js projects. By automating the generation of type definitions and query builders, codegen simplifies the development process and ensures a seamless communication between the frontend and backend. Leveraging code generation tools like GraphQL Codegen enhances productivity, improves type safety, and reduces the overhead of manual code maintenance. Incorporating code generation into your Next.js projects can significantly boost development efficiency and streamline API integration.

Useful Links/Resources: