Challenge
Inconsistent API integrations could lead to data loss or even application crashes. In this article, I am going to share with you how I interact safely with GraphQL API in Next.js.
Solution
The answer to this challenge is using GraphQL Code Generators to create TypeScript clients from GraphQL schemas and GraphQL operations. When the schema from the server changes, we can create a new TypeScript client with a single command.
And thanks to the power of TypeScript, we can spot where to update our code immediately by running the TypeScript compiler.
Choose a GraphQL Code Generator
There are many code generators out there, such as graphql-codegen, graphql-zeus, genql, gqless, etc. Each one has its advantages and disadvantages.
I have had working experience with graphql-codegen since 2019 in Version 1 and Version 2 of the Next Shopify Storefront
project. In my opinion, graphql-codegen
is super reliable; the only drawback is you must write queries and mutations in pure GraphQL to create TypeScript clients.
The other choices are graphql-zeus, genql. I have worked with both of them on my private projects, along with hasura graphql engine. The advantage of them is you don't need to write GraphQL code to generate TypeScript clients. Instead, you need to write queries and mutations in TypeScript to interact with GraphQL servers.
To simplify the way I interact with GraphQL APIs, I prefer to use graphql-zeus over graphql-codegen
. graphql-zeus is also better than genql
when it comes to bundle size. You can find my comparison here: https://github.com/maxvien/shopify-graphql-zeus-vs-genql
Create a TypeScript Client with GraphQL Zeus
Now I will show you how I create a TypeScript client from Shopify Storefront GraphQL API with GraphQL Zeus.
First, we need an apiEndpoint
and an accessToken
from Shopify. In this article, I will use the available API information below. You can follow the Shopify storefront documentation to get yours.
const apiEndpoint = 'https://graphql.myshopify.com/api/2023-01/graphql.json';
const accessToken = 'dd4d4dc146542ba7763305d71d1b3d38';
Next, we will install graphql-zeus
in our Next.js project with TypeScript support.
npm install --save-dev graphql-zeus
And with the API information above, we can run this command to create our TypeScript client inside ./src/utilities/storefront
.
npx zeus https://graphql.myshopify.com/api/2023-01/graphql.json ./src/utilities/storefront --header=X-Shopify-Storefront-Access-Token:dd4d4dc146542ba7763305d71d1b3d38
In the ./src/utilities/storefront
folder, we create a index.ts
file like this to configure our client.
import { Thunder } from './zeus';
const apiEndpoint = 'https://graphql.myshopify.com/api/2023-01/graphql.json';
const accessToken = 'dd4d4dc146542ba7763305d71d1b3d38';
const chain = Chain(apiEndpoint, {
headers: {
'Content-Type': 'application/json'
'X-Shopify-Storefront-Access-Token': accessToken,
},
});
export const storefront = {
query: chain('query'),
mutation: chain('mutation'),
};
export * from './zeus';
In case, you want to implement GraphQL Zeus
with Shopify Hydrogen React you can follow my configurations here: codegen.mjs, src/utilities/storefront/index.ts.
Write GraphQL Operations with GraphQL Zeus
Now we can use our client to write queries and mutations safely with TypeScript. It will take a little time to familiar with writing GraphQL operations in TypeScript. But it is worth it! It improves your development experience with GraphQL.
import { storefront } from "../utilities/storefront";
const { products } = await storefront.query({
products: [
{ first: 12 },
{
pageInfo: {
hasNextPage: true,
},
edges: {
cursor: true,
node: {
handle: true,
title: true,
priceRange: {
minVariantPrice: {
amount: true,
currencyCode: true,
},
},
featuredImage: {
url: [{ transform: { maxWidth: 500 } }, true],
altText: true,
width: true,
height: true,
},
},
},
},
],
});
console.log(products);
Conclusion
That is how I handle GraphQL API integrations in Next.js. I hope my little solution can help you consume GraphQL API more safely throughout the development cycle. Thank you for reading!