Working with GraphQL Code Generator and GraphCMS

Jamie Barton
Jamie Barton

June 14, 2021

GraphQL Code Generator is an awesome open source project by The Guild that generates code from your GraphCMS schema.

In this post I'll show how you can install, configure, and generate your first query with Apollo Client using GraphQL Code Generator. This post assumes you are using React, and have Apollo Client already setup.

Install

First, let's begin by installing graphql and @graphql-codegen/cli.

npm install graphql
npm install --save-dev @graphql-codegen/cli

Next, run the initialization wizard.

npx graphql-codegen init

You'll be asked a series of questions:

What type of application are you building? Feel free to pick the relevant one, I'll be using React through this post.

Where is your schema? You'll want to enter your GraphCMS endpoint here. For example, https://api-eu-central-1.graphcms.com/v2/ck8sn5tnf01gc01z89dbc7s0o/master

You can follow this article by using the same endpoint if you don't have a project setup already.

You can later change this to be an ENV variable.

Where are your operations and fragments? If you haven't any existing GraphQL queries, mutations, or fragments defined in your project, just hit enter to accept the default.

Pick plugins Now you'll want to select the plugins, we'll go ahead and pick TypeScript, TypeScript operations, and TypeScript React Apollo.

Where to write the output? This is where the generated code is output. Since we used TypeScript allow, the file extension will be .tsx - as it includes Apollo Client hooks.

Do you want to generate an introspection file? Yes we do!

How to name the config file? The default codegen.yml is good - unless you have a strong preference otherwise.

What script in package.json should run the codegen? Personally I like just calling it codegen.

Now we'll need to install the plugins we selected:

npm install

Once everything is installed, you'll need to have some queries before try to generate any code!

Configure

Let's create a simple query inside src/queries/products.graphql:

query allProducts(
$orderBy: ProductOrderByInput
$first: Int
$skip: Int
$where: ProductWhereInput
) {
products(orderBy: $orderBy, first: $first, skip: $skip, where: $where) {
...ProductSummary
}
}
fragment ProductSummary on Product {
id
name
slug
description
publishedAt
}

This query uses arguments for filtering, paginating, and ordering your products. You can inspect your GraphCMS GraphQL schema to see all possible input types for your own GraphQL types.

Now we've a GraphQL query, we can go ahead and run the code generator:

npm run codegen # or whatever the script was you named

You should now see the file src/generated/schema.tsx (if you kept the default output filename), and inside here if you scroll to the bottom, there will be some generated Apollo Client hooks.

Repeat this for any GraphQL queries, or mutations you use within your application. You can also "watch" for any changes, and automatically run the code generator!

Usage

Now we'll use the automatically generated query inside our code. Inside your application, import the hook, and input type to better type your page.

import {
useAllProductsQuery,
ProductOrderByInput,
} from './generated/schema.tsx';

Then invoke the useAllProductsQuery hook and pass it some variables to order the results.

const { loading, error, data } = useAllProductsQuery({
variables: { orderBy: ProductOrderByInput.PublishedAtDesc },
});

As you can see, we're using the auto generated value for PublishedAtDesc from the schema for ultimate type safety.

Next, let's render loading if we're loading, and render that we have an error if one is defined.

if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;

Then on your page render the list of products if we've got data:

<ul>
{data &&
data.products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>

If you type the above without copy/pasting, you'll notice the autosuggest for [product.id](http://product.id) and [product.name](http://product.name) - this is based off the fragment we defined earlier. ✨

Going further

With the example schema I shared above, products have a relation to votes. A product can have many votes.

Let's now write a query inside our application that fetches products where there are no votes. We'll need to import ProductSummaryFragment so we can properly type our function.

import { ProductSummaryFragment } from './generated/schema.tsx';
function useOneProductWithoutVote(): ProductSummaryFragment | undefined {
const { data } = useAllProductsQuery({
variables: { where: { votes_none: {} }, first: 1 },
});
return data?.products[0];
}

We can then invoke this function:

const { loading, error, data } = useAllProductsQuery({
variables: { orderBy: ProductOrderByInput.PublishedAtDesc },
});
const aProductWithoutVote = useOneProductWithoutVote();
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<>
<h2>Our products</h2>
<ul>
{data &&
data.products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
{aProductWithoutVote && (
<>
<h2>Don't forget to vote on: </h2>
<p>{aProductWithoutVote.name}</p>
</>
)}
</>
);

Hopefully you've found this article useful in getting started with GraphCMS + GraphQL Code Generator. GraphQL Code Generator not only saves you a lot of time by automatically generating code, but it generates code that is type safe.

You can view the code for this example on GitHub.


It's Easy To Get Started

GraphCMS plans are flexibly suited to accommodate your growth. Get started for free, or reach out to our sales team to discuss larger projects with more complex needs