post picture
How to use GraphQL Code Generator with React and Apollo
Published: 4 July 2022

GraphQL is a great way to build apps faster. But, if you're only using GraphQL without a GraphQL Code Generator you're missing out on the full potential of GraphQL.

In this blog post, you'll learn how to use the missing piece (GraphQL Code Generator) to unleash the full potential of GraphQL with React and Apollo Client.

To understand how to use the full potential of GraphQL we need to understand the concept of data types and why they are important.

What is a data type?

If you're a developer I'm sure you've come across data types before.

Some common data types:

  • Boolean

  • Integer

  • String

A data type, or simply type, is metadata about the data itself. A developer and programming language use this metadata to understand what the data can be used for.

Why is type-safety important?

Type-safe languages prevent type errors and are generally more robust and have fewer bugs.

Type-safety prevents you from accidentally using a data type that doesn't match the type you're expecting.

Like multiplying an integer and a string.

const a = 4;
const b = 'Joe';
const c = a * b;

Or trying to loop over a variable that is not an array.

const a = true;
a.map((b) => {
  console.log(b);
});

It's a huge win if you can catch these errors when your developing, instead of them leading to bugs in your application.

Every GraphQL API is type-safe. And if you're using Nhost with Hasura your GraphQL API is generated from tables and columns in Postgres, which is also type-safe.

This means you have a type-safe chain from your database to your GraphQL API. This is great news, as your database and API are now safe from type errors.

Ideally, this type-safe chain should not stop at the GraphQL API. It should continue to your frontend application where you run TypeScript.

TypeScript is a type-safe language that is a superset of JavaScript. It's a great language to prevent type errors, which leads to fewer bugs and more robust applications.

It's, therefore, no surprise that TypeScript is one of the most popular languages in the world!

npm trend for TypeScript

npm trend for TypeScript

If you're not familiar with TypeScript, and don't want to re-write your whole application from JavaScript to TypeScript, you can gradually adopt TypeScript in your JavaScript application. There are some good resources online on how to gradually adopt TypeScript.

Ok. So let's say you're using Postgres and GraphQL for your backend and TypeScript for your frontend. You have type-safety both on your backend and on your frontend.

The only problem is, that you don't have type-safe between the GraphQL API and TypeScript.

TypeScript can not automatically understand what types are in your GraphQL API. So when you're fetching data via GraphQL, TypeScript does not know what types the data in your GraphQL API is.

That's why you need GraphQL Code Generator.

GraphQL Code Generator is the glue between your GraphQL API and TypeScript. It will automatically generate TypeScript code based on your GraphQL API.

Once you have that, you have end-to-end type-safety, from your database, via your GraphQL API, to your frontend code with TypeScript.

Let's unleash the full power of GraphQL and type-safety in your app.

Setup

Three simple steps are required to set up GraphQL Code Generator:

  1. Install a few npm packages.

  2. Create a GraphQL Code Generator configuration file.

  3. Add a GraphQL Code Generator script to the package.json file.

Let's get started.

Install NPM packages

Install the following npm packages required to run GraphQL Code Generator, generate types for TypeScript, and generate hooks and helper functions for React and Apollo.

npm install --dev @graphql-codegen/cli @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo graphql
# or yarn
yarn add -D @graphql-codegen/cli @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo graphql
# or pnpm
pnpm add -D @graphql-codegen/cli @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo graphql

Create a Config File for GraphQL Code Generator

Next, create a graphql.config.yaml file in the root of your git repo.

This configuration file contains information about:

  • Your GraphQL API.

  • Where to find GraphQL queries and mutations in your code.

  • What types and hooks to generate.

Here's the configuration file. Update the file with your GraphQL endpoint. If you're using Nhost and Hasura you also need to add the admin secret so the GraphQL Code Generator can read your whole GraphQL API.

schema:
  - https://<subdomain>.graphql.<region>.nhost.run/v1:
      headers:
        x-hasura-admin-secret: <your-admin-secret>
documents:
  - 'src/**/*.graphql'
generates:
  src/utils/__generated__/graphql.ts:
    plugins:
      - 'typescript'
      - 'typescript-operations'
      - 'typescript-react-apollo'
    config:
      withRefetchFn: true

Add a Codegen Script to package.json

As a last step, let's add a script to the package.json to run GraphQL Code Generator.

{
  /*...*/
  "scripts": {
    /*...*/
    "codegen": "graphql-codegen --config graphql.config.yaml --errors-only"
  }
  /*...*/
}

You'll run this script (npm run codegen) every time you've changed anything in your GraphQL API or in your GraphQL files to get the most up-to-date types generated.

You've now completed the three configuration steps. It's time to start using the GraphQL Code Generator and unleash its power!

Workflow

As a mental model, this is how you will use the GraphQL Code Generator in your development workflow:

  1. Manage GraphQL queries and mutations in .graphql files

  2. Run npm run codegen to generate types and hooks for queries, mutations, and subscriptions.

  3. Use the hooks and types in your React app.

Example

We'll go through two examples of how to use your new GraphQL Code Generator setup. One is using a query to fetch data and one is using a mutation to modify data.

In the examples, we're using Apollo with React. To learn how to set up Apollo with React (and Next.js), follow our guide in our documentation: Apollo GraphQL with React and Nhost.

For the two examples, we're using a table customers in Hasura with two columns:

  • id - UUID

  • name - Text

Go ahead and create the customers table. As said, we'll use it for the two following examples.

If you already have an exsiting GraphQL schema that works too. Just make sure to change the GraphQL queries and mutations accordingly.

Get Customers (Query)

As we mentioned under the Workflow section above, we use the three-step process when using GraphQL Code Generator.

Just to repeat, these are the three steps:

  1. Manage GraphQL queries and mutations in .graphql files

  2. Run npm run codegen to generate hooks and types for queries, mutations, and subscriptions.

  3. Use the hooks and types in your React app.

Let's get going.

Add the following GraphQL query in src/graphql/customers.graphql:

query getCustomers {
  customers {
    id
    name
  }
}

Bonus: If you're using VS Code and the GraphQL extension you'll get autocompletion when writing GraphQL in VS Code. This works because you added the graphql.config.yaml before and specified your schema and admin secret.

GraphQL Autocomplete in VS Code

GraphQL Autocomplete in VS Code

Run the codegen to generate types and hooks:

npm run codegen

Use the generated hook in react:

import { useGetCustomersQuery } from '../utils/__generated__/graphql';

export function Customers() {
  const { data, loading, error } = useGetCustomersQuery();

  if (loading || !data) {
    return <div>Loading</div>;
  }

  if (error) {
    return <div>Error</div>;
  }

  const { customers } = data;

  return (
    <div>
      <h2>Customers</h2>
      <ul>
        {customers.map((customer) => (
          <li key={customer.id}>{customer.name}</li>
        ))}
      </ul>
    </div>
  );
}

That's it. You now have type-safety from Postgres, to GraphQL to TypeScript. Good job!

Now, let's see some other benefits.

If you're trying to access a property on customers that does not exist, TypeScript will throw an error. E.g. if you're trying to access customer.address.

ERROR in src/components/customers.tsx:21:43
TS2339: Property 'address' does not exist on type '{ __typename?: "customers" | undefined; id: number; name: string; }'.
    19 |       <ul>
    20 |         {customers.map((customer) => (
  > 21 |           <li key={customer.id}>{customer.address}</li>
       |                                           ^^^^^^^
    22 |         ))}
    23 |       </ul>
    24 |     </div>

If you're using VS Code you also see the error from TypeScript while you're coding

VS Code shows TypeScript error.

VS Code shows TypeScript error.

TypeScript also knows that customer.name is of type string, which it has inferred from Postgres (customers.name is of type text) and GraphQL (customers.name is of type string). This means you can't use customer.name to perform arithmetic operations.

VS Code shows another TypeScript error.

VS Code shows another TypeScript error.

As you see, with the GraphQL Code Generator (and Postgres, GraphQL and TypeScript) you're less likely to run into type errors. Overall, your application becomes more robust with fewer bugs!

Let's continue and see how to use GraphQL Code Generator with GraphQL mutations.

Insert Customer (Mutation)

Add the following GraphQL mutation in the same src/graphql/customers.graphql file:

mutation InsertCustomer($customer: customers_insert_input!) {
  insert_customers_one(object: $customer) {
    id
  }
}

Again, run the codegen script to generate new types and hooks for our newly added GraphQL mutation:

npm run codegen

Now, use the generated useInsertCustomerMutation hook in your React app.

import { useState } from 'react';
import {
  refetchGetCustomersQuery,
  useInsertCustomerMutation,
} from '../utils/__generated__/graphql';

export function NewCustomer() {
  const [name, setName] = useState('');

  const [insertCustomer, { loading, error }] = useInsertCustomerMutation({
    refetchQueries: [refetchGetCustomersQuery()],
  });

  const handleSubmit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
    e.preventDefault();

    try {
      await insertCustomer({
        variables: {
          customer: {
            name,
          },
        },
      });
    } catch (error) {
      return console.error(error);
    }

    setName('');

    alert('Customer added!');
  };

  return (
    <div>
      <h2>New Customer</h2>
      <div>
        <form onSubmit={handleSubmit}>
          <div>
            <input
              type="text"
              name="name"
              placeholder="Name"
              value={name}
              onChange={(e) => setName(e.target.value)}
            />
          </div>
          {error && <div>Error: {error.message}</div>}
          <div>
            <button type="submit" disabled={loading}>
              Add
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

GitHub Repository

The example code for this blog post is on GitHub - GraphQL Code Generator Example Repository.

Summary

In summary, this is what you've learned:

  • What types are

  • Why types are important

  • How types can help you build robust applications with fewer bugs

  • How to configure and use GraphQL Code Generator with React, Apollo, and TypeScript.

What's next?

Did you enjoy this blog post?

⭐ Show your support and star us on GitHub!

We use cookies to provide our services and for analytics and marketing. By continuing to browse our website, you agree to our use of cookies.
To find out more about our use of cookies, please see our Privacy Policy and Cookies Policy.