GraphQL API Requests with Typescript, React Query & GraphQL Code Generator

GraphQL API Requests with Typescript, React Query & GraphQL Code Generator

In this article, we'll learn how to make GraphQL requests in the client-side of our React application with React Query, Typescript(TS) and also automatically generate TS types for our queries with GraphQL Code Generator. The following paragraphs will be explaining the essence of these technologies.

The first is Typescript(TS) which is gaining huge popularity these days and lots of developers are migrating their projects from plain Javascript to TS. Typescript being a superset of Javascript provides optional static typing making it easy to detect errors during development.

Next is GraphQL, a query language for APIs. With GraphQL, developers can get all the data needed in their application in a single request without having to under-fetch or over-fetch, unlike in REST APIs. One cool feature about GraphQL is the fact that it uses a type system(schema) to describe data queries and mutations.

Now leveraging on this feature of GraphQL schema being typed, we can turn it into Typescript types in our application frontend offering you a better developer experience since they are both typed. But, to ensure type-safety we'll be using a tool called GraphQL Codegen to help us auto-generate correct types based on our schema and also get fully typed custom React hooks for React Query.

Moving on, as developers, there are scenarios where we might not want to use a heavyweight library to fetch GraphQL API for example Apollo in our projects but would prefer a lightweight library to perform the operation. This is where React Query(a library that interacts with our API) comes into play coupled with a library called graphql-request which is pretty much like Axios or fetch but tailored to make just graphql requests.

Let's go ahead to setup the project!

Prerequisites

This article will assume you have some familiarity with using React Query and Typescript. Also, basic knowledge of GraphQL will come in handy.

Create React App

To create a new React app with the --typescript template flag, run;

yarn create react-app client --template typescript

If you're having issues creating a new react app due to the recent version upgrade, check out this article on how to fix it.

Then, start the development server by running

yarn start

Setup React Query

Let's install React Query library by executing the following command;

yarn add react-query

Then, open up the index.tsx file in the project folder and set up React Query client;

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

import { QueryClient, QueryClientProvider } from "react-query";

const queryClient = new QueryClient();

ReactDOM.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>,
  document.getElementById('root')
);

Here we instantiated the React query client and then wrapped our top-level component within the React query client provider.

Scaffolding out the App

In the src folder of the project, create a folder called components. Right in this components folder, create a Countries.tsx file. The Countries component will display lists of countries from the free public GraphQL Countries API we'll be using in this tutorial.

For the purpose of styling the component interface, Tailwind CSS will be used. Now, add the CDN link written below to the head tag of the public/index.html file.

<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">

In the Countries component, add the following code;

import React from "react";

const Countries: React.FunctionComponent = () => {

  return (
          <div className="bg-white rounded-lg shadow-md w-80 text-center">
            <div className="mt-4 p-10 text-bold">
              <p>Country</p>
              <p>Capital</p>
              <p>Continent</p>
            </div>
          </div>
  );
};

export default Countries;

Next, open the App.tsx file in the project folder and update like so

import React from "react";

import Countries from "./components/Countries";

const App = () => {
  return (
    <>
      <div className="bg-blue-100">
        <header className="text-3xl text-center font-bold pt-6">Countries</header>
        <div className="flex justify-center pb-2">
          <div className="flex flex-col">
            <div className="flex-grow">
              <div className="m-4 grid grid-cols-2 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-2 gap-8 mt-8">
                <Countries />
              </div>
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

export default App;

Install GraphQL-Request Library

This library will basically provide a function that accepts an endpoint. Type the following command in your terminal, so we can install graphlql-request into our project

yarn add graphql graphql-request

The graphql added above is a dependency for graphql-request.

Now update the Countries component like so

import React from "react";

import { GraphQLClient } from "graphql-request";

const graphqlClient = new GraphQLClient(
  "https://countries.trevorblades.com/graphql"
);

const Countries: React.FunctionComponent = () => {

  return (
          <div className="bg-white rounded-lg shadow-md w-80 text-center">
            <div className="mt-4 p-10 text-bold">
              <p>Country</p>
              <p>Capital</p>
              <p>Continent</p>
            </div>
          </div>
  );
};

export default Countries;

Here, we basically imported GraphQLClient from graphql-request and instantiated it.

Write Queries

Next, we need to create a countries.graphql file in the src folder. In this file, we'll define a query to get the list of countries data we need; the country names, capital and continents.

query Countries {
    countries {
        name
        capital
        continent {
            name
        }
    }
}

Setup GraphQL Codegen

Now, let's install graphql-code-generator so we can have it up and running in our application. Execute the following command;

yarn add -D  @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-react-query  @graphql-codegen/typescript-operations

From the above, we installed

  • graphql-codegen CLI so we can run our codegen script.
  • graphql-codegen/typescript and graphql-codegen/typescript-operations plugins so we can get our generated types.
  • graphql-codegen/typescript-react-query plugin in order to generate custom React Query hooks.

Let's also create a codegen.yml file where we'll configure how we want our code to be generated.

overwrite: true
schema: "https://countries.trevorblades.com/graphql"
documents: "src/**/*.graphql"
generates:
  src/generated/index.ts:
    plugins:
      - typescript
      - typescript-operations
      - typescript-react-query
    config:
        fetcher: graphql-request
  • schema is the URL for the free public GraphQL API we are using in this tutorial.
  • documents tells graphql-codegen to locate graphql files, in this case the countries.graphql file.
  • generates defines the file path where the types will be generated once we run a defined graphql-codegen script.
  • plugins represents the plugins we installed earlier.
  • fetcher configuration lets graphql-codegen know we are using graphql-request to fetch our data.

Then, let's add our graphql-codegen script into our package.json file like so;

codegen.PNG

Next, let's run our script so we can have generated custom types added automatically to our project src as a folder titled generated;

yarn generate

Display the Data

In the Countries componet, let's update our code as shown below;

import React from "react";

import { GraphQLClient } from "graphql-request";

import { CountriesQuery, useCountriesQuery } from "../generated";

const graphqlClient = new GraphQLClient(
  "https://countries.trevorblades.com/graphql"
);

const Countries: React.FunctionComponent = () => {
  const { data, isLoading, error } = useCountriesQuery<CountriesQuery, Error>(
    graphqlClient,
    {}
  );

  if (isLoading) {
    return <div className="box">Loading...</div>;
  }

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

  return (
    <>
      {data?.countries?.map((country) => {
        return (
          <div className="bg-white rounded-lg shadow-md w-80 text-center">
            <div className="mt-4 p-10 text-bold">
              <p>Country: {country.name}</p>
              <p>Capital: {country.capital}</p>
              <p>Continent: {country.continent.name}</p>
            </div>
          </div>
        );
      })}
    </>
  );
};

export default Countries;

From the code above, to interact with the Countries API we are importing the fully typed custom hooks generated by graphql-codegen in place of the usual useQuery hook from React Query library. Then, we looped through the response data to display the lists of countries, capital and continents.

Now you have it!. The final application should look like this;

display.PNG

You can access the project source code in this Github repo. Thanks for reading!

Conclusion

In this article, we were able to make GraphQL API request successfully in our client-side application. By also incorporating the power of the GraphQL codegen library, we were able to generate fully typed custom React Query hooks for our application from the GraphQL schema.