Supercharge your React-native app with GraphQL Codegen: Strongly typed, hassle-free data fetching

Omal Perera
Ascentic Technology
9 min readOct 31, 2023

--

Image By Sketchepedia

As we all know, graphQL is a query language for APIs that enables more efficient and precise data retrieval. It allows clients to request exactly the data they need, eliminating over-fetching or under-fetching. GraphQL offers a strongly typed schema, defining what data can be queried, and allows for complex, nested queries in a single request. It’s a versatile and flexible technology, well-suited for modern, data-driven applications, and enables developers to iterate on the client side without requiring changes on the server.

Nowadays, TypeScript is our preferred choice for many JavaScript projects, offering numerous advantages such as type safety, enhanced code quality, improved documentation, reduced bugs, and more.

GraphQL Code Generator

GraphQL Code Generator (GraphQL Codegen) is a tool and code generation framework that automates the process of generating code from your GraphQL schema and operations. GraphQL is a query language for your API, and GraphQL Codegen helps streamline the development process by generating strongly typed code for your API.

Here’s how GraphQL Codegen works and what it can do:

  1. Schema-first development:
    GraphQL Codegen typically starts with a GraphQL schema definition. You define your data types, queries, mutations, and subscriptions in a schema file. GraphQL Codegen can then generate code for your server and client based on this schema.
  2. Type-safe code:
    GraphQL Codegen generates code in various programming languages (eg: JavaScript, TypeScript, Java, Go) that enforces type safety. This means that you can work with your GraphQL data and queries without worrying about type-related runtime errors.
  3. Client-side code generation:
    For client applications, GraphQL Codegen can generate code to create GraphQL queries and mutations. This eliminates the need to write these queries manually, reducing errors and speeding up development.
  4. Integrations with build tools:
    GraphQL Codegen can be integrated into your build process, ensuring that generated code is always up-to-date with your schema and queries. It can be used with tools like Webpack, Babel, and others.
  5. Integrations with build tools:
    GraphQL Codegen supports various GraphQL libraries, such as Apollo Client, Relay, and many server frameworks. This makes it a versatile tool that can be adapted to your project’s requirements.

Let’s configure GraphQL codegen

Image courtesy — giphy.com

Let’s take a look at how to set up the required configurations. This article focuses on doing it in a React Native project (which is almost similar to React projects as well). If you’re interested in using GraphQL Codegen in other languages, you can visit https://the-guild.dev/graphql/ codegen for instructions.

If you want to skip the RN project initialization and graphQL initialization, you can directly refer to Step 6 and onwards.

Step 1 — Creating a base react-native project

  1. I’m assuming that you’ve already set up your React Native development environment on your local machine. If not, you can visit the official React Native documentation for step-by-step instructions.
  2. Now, let’s run the following command to create a new project
npx react-native@latest init RnGql

Step 2 — Checking newly created app is running correctly

  1. Navigate to the project directory and run the project to ensure everything is working smoothly with your React Native project.
cd RnGql 
react-native run-android

Step 3 — Let’s start with initiating a graphQL client

  1. We will use the Apollo client to make GraphQL requests in our RN application npm i @apollo/client
  2. For this demonstration, we’ll be using AniList, a free GraphQL service where we can request sample anime data. You can find more information at https://anilist.gitbook.io/anilist-apiv2-docs/overview/graphql/getting-started.
  3. Create a folder named src in your project directory.
    Move the App.tsx file into the src folder and update the import statement in index.js.
  4. Inside the src folder, create a new folder called animeList (for later use).
  5. Let’s define a GraphQL client. Create a new directory called network within the src folder.
    Inside the network directory, create a new file named graphqlClient.ts and add the following lines.
    Add another folder called queries inside network folder for later use.
import {ApolloClient, InMemoryCache} from '@apollo/client';

export const client = new ApolloClient({
uri: 'https://graphql.anilist.co',
cache: new InMemoryCache(),
});

so at the end of this step, your files folder structure should be as follows.

The newly added network directory and the graphqlClient file.

Step 4— Build up a simple query & add it to our project

Now, we’re going to create a simple query to retrieve a list of anime data from AniList. Go to https://anilist.co/graphiql and write a query to fetch 10 anime items. To keep things straightforward, we’ll only retrieve 2 properties per item.

creating a simple query in https://anilist.co/graphiql, which we can use in the project

Incorporating the above query into our React native codebase and generating the required code using GraphQL Codegen involves a few steps:

  1. Inside the queries directory, craft a new file named anime.graphql (remember to include the ‘.graphql’ extension, which aids in recognizing query files during code generation).
  2. Copy and paste the query we crafted in the previous step into this file. Additionally, we have given a name and the ability to pass variables to the query.
query GetAnimeList($page: Int, $perPage: Int) {
Page(page: $page, perPage: $perPage) {
media {
id
title {
userPreferred
}
seasonYear
}
}
}

Step 5 — Develop a simple view component to render data

  1. Create a file named animeListView.tsx in animeList folder we created in step 3 earlier.
  2. Add the following code to animeListView.tsx
    Note: we are running our component with a fixed constant array as our graphQL codegen is still not fully configured. we will be replacing this in the final step.
import React from 'react';
import {FlatList, StyleSheet, Text, View} from 'react-native';

// still codegen is under configuration. so defining a sample array to test the component
const animeList = {
Page: {
media: [
{
id: 1,
title: {
userPreferred: 'Cowboy Bebop',
},
seasonYear: 1998,
},
{
id: 5,
title: {
userPreferred: 'Cowboy Bebop: Tengoku no Tobira',
},
seasonYear: 2001,
},
],
},
};

const AnimeListViewComponent = () => {
const renderAnimeItem = item => {
return (
<View style={styles.itemContainer}>
<Text>{item.title?.userPreferred}</Text>
<Text>{item.seasonYear}</Text>
</View>
);
};

return (
<View style={styles.contentContainer}>
<FlatList
data={animeList.Page.media}
renderItem={({item}) => renderAnimeItem(item)}
refreshing={false}
/>
</View>
);
};

export default AnimeListViewComponent;

const styles = StyleSheet.create({
contentContainer: {
flex: 1,
flexDirection: 'column',
},
itemContainer: {
flex: 1,
flexDirection: 'row',
marginVertical: 5,
marginHorizontal: 15,
justifyContent: 'space-between',
},
});

And replace the code in App.tsx as below.

Don't forget to wrap the component tree with a <ApolloProvider client={client}

import React from 'react';
import {SafeAreaView} from 'react-native';
import AnimeListViewComponent from './animeList/animeListView';
import {ApolloProvider} from '@apollo/client';
import {client} from './network/graphqlClient';

function App(): JSX.Element {
return (
<ApolloProvider client={client}>
<SafeAreaView />
<AnimeListViewComponent />
</ApolloProvider>
);
}

export default App;

Step 6 — Real codegen configuration

To accomplish this, we’ll need the assistance of the following additional development dependencies for this task.

  1. @graphql-codegen/cli: CLI tool for generating code based on GraphQL schemas and operations.
  2. @graphql-codegen/typescript: designed to generate TypeScript code from your GraphQL schema
  3. @graphql-codegen/typescript-graphql-request: creates functions and code that help you send queries, mutations, and subscriptions to a GraphQL server.
  4. @graphql-codegen/typescript-operations: this is a template plugin
  5. @graphql-codegen/typescript-react-apollo: this is a template plugin (we can specify different templates. As I mentioned in the very beginning code gen support for many frameworks and languages. If our requirement is to go with relay instead of Apollo, we can generate compatible code by adjusting these template plugins)

install the above dev dependencies.

npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-graphql-request @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo

Create a new file named graphql.config.yml in the project root directory. Then, include the following code. For further information about the configuration file, you can refer to the documentation here. (https://the-guild.dev/graphql/config/docs/user/usage).

schema:
- 'https://graphql.anilist.co'
documents:
- './src/**/*.graphql'
generates:
./src/network/queries/__generated__/graphql.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo

here we have Instructed the Codegen CLI tool to scan all *.graphql files within the source directory, generate code based on provided templates, and save it to the src/network/queries/__generated__/graphql.ts

As the final step of our configurations, add the following line to the Package.json file. This will help to run the codegen tool from CLI.

"scripts": {
...,
"generate-gql-queries": "graphql-codegen --config graphql.config.yml"
},

Now run the above-added script in your terminal in the root directory using

npm run generate-gql-queries
Executing codegen command in terminal and get the success response.

If you can see the results above. Congratulations! 🎉🎉🎉

Step 7 — Check the generated code

Now if you check the src/network/quaries folder, there will be a newly generated file with all generated codes.

codegen output

If you explore the graphql.ts file. You’ll find a complete set of generated type definitions and queries, along with examples illustrating how to use them.

Generated code, type definitions from codegen

The challenging part is behind you. Now, all that’s left is to use the generated items in your React Native project

To utilize the generated code in your React Native project, you have access to code blocks for useQuery hook, useLazyQuery hook, and the plain query document. You’re free to use them as you see fit.

  1. using useQuery hook
import { useGetAnimeListQuery } from '../network/queries/__generated__/graphql';

const {data, loading, error} = useGetAnimeListQuery({
variables: {
page: 1,
perPage: 10,
},
});

2. using useLazyQuery hook

import { useGetAnimeListLazyQuery } from '../network/queries/__generated__/graphql';

const [getAnimeList, {data, loading, error}] = useGetAnimeListLazyQuery({
variables: {
page: 1,
perPage: 10,
},
});

const onRefresh = () => {
getAnimeList();
};

3. using plain query document

import { GetAnimeListDocument } from '../network/queries/__generated__/graphql';
import {client} from '../network/graphqlClient';


const fetchAnimeList = async () => {
const {data, loading, error} = await client.query({
query: GetAnimeListDocument,
variables: {
page: 1,
perPage: 10,
},
});
};

This is how it will be used in our example component.

import React from 'react';
import {FlatList, StyleSheet, Text, View} from 'react-native';
import {
GetAnimeListDocument,
useGetAnimeListLazyQuery,
useGetAnimeListQuery,
} from '../network/queries/__generated__/graphql';
import {client} from '../network/graphqlClient';

const AnimeListViewComponent = () => {
/* Method 1 - Using useQuery */
const {data, loading, error} = useGetAnimeListQuery({
variables: {
page: 1,
perPage: 10,
},
});

/* Method 2 - Using useLazyQuery */
// const [getAnimeList, {data, loading, error}] = useGetAnimeListLazyQuery({
// variables: {
// page: 1,
// perPage: 10,
// },
// });

// const onRefresh = () => {
// getAnimeList();
// };

/* Method 3 - If you are using the query document */
// const fetchAnimeList = async () => {
// const {data, loading, error} = await client.query({
// query: GetAnimeListDocument,
// variables: {
// page: 1,
// perPage: 10,
// },
// });
// };

const renderAnimeItem = item => {
return (
<View style={styles.itemContainer}>
<Text>{item?.title?.userPreferred}</Text>
<Text>{item?.seasonYear}</Text>
</View>
);
};

return (
<View style={styles.contentContainer}>
<FlatList
data={data?.Page?.media || []}
renderItem={({item}) => renderAnimeItem(item)}
refreshing={loading}
//onRefresh={onRefresh} //uncomment if you use 'Method 2 - useLazyQuery'
/>
</View>
);
};

export default AnimeListViewComponent;

const styles = StyleSheet.create({
contentContainer: {
flex: 1,
flexDirection: 'column',
},
itemContainer: {
flex: 1,
flexDirection: 'row',
marginVertical: 5,
marginHorizontal: 15,
justifyContent: 'space-between',
},
});

And also now you have the type definitions too.

How codegen provides type definitions.

That is it!

In conclusion, GraphQL Codegen is a powerful tool that streamlines the development process in TypeScript-based React Native projects. By automating the generation of strongly typed GraphQL code, it enhances code quality, reduces errors, and boosts developer productivity. Whether you’re building a complex mobile app or a simple prototype, integrating GraphQL Codegen ensures that your data-fetching code remains type-safe and maintainable, allowing you to focus on creating outstanding user experiences in your applications.

Codebase: https://github.com/OmalPerera/RnGql

--

--