Apr 25, 2020

Rapidly Setting up GraphQL Data Fetching in React

Setting up the groundwork for querying your backend APIs should be a quick process, not fiddling around with configuration. Often it can be intimidating to integrate libraries to manage connectivity, caching, and other important features your application is going to benefit from, which is one of the reasons for the massive adoption of Apollo Client. But this alone still requires you to put in the time to write your queries, and, when using TypeScript, to declare your types. I've been able to kickstart a flexible setup revolving around apollo-boost (which can be replaced with the fully-fledged version easily) and GraphQL Code Generator, an amazing project by the Guild. Everything from generating code and types for my queries to receiving fully-typed responses in the form of a React hook is covered by the seemingly-simple configuration.

You can start your stopwatch now, I guarantee it will take less than 10 minutes until you're set up with a fully-featured data-fetching pipeline powered by the libraries outlined above. Let's go!

šŸ“ Prerequisites

Before we get started, we'll want to create a sample React application using TypeScript, you can go with your favorite choice, I'll use create-react-app since I want to spend my time on building the application rather than fighting with any SSR or SSG process for now.

# Create your application starter
npx create-react-app my-app --template typescript

šŸ“” Setting up Apollo Client

To fetch any data from our GraphQL endpoint, we need to install a client library to allow our application to communicate with the backend in place. Of course, we could just write a simple fetch with changing bodies, but since we'll need to handle errors and probably also cache responses for when we repeatedly ask for the same data, it makes sense to go with a solution that offers more.

$ yarn add apollo-boost @apollo/react-hooks graphql

Apollo Boost is a collection of carefully-picked packages around Apollo Client that makes it simple to get started with an all-in-one solution (except it doesn't support subscriptions, but that's fine for now).

In our React app, let's create a client to use for fetching data:

import ApolloClient from 'apollo-boost';

const client = new ApolloClient({
  uri: '<Our endpoint>'
});

Since we don't want to pass our client around all the time, we'll also add an ApolloProvider to keep track of our client and supply the hooks we'll use later.

import React from 'react';
import { render } from 'react-dom';

import { ApolloProvider } from '@apollo/react-hooks';

// <Our client code from above>

const App = () => (
  <ApolloProvider client={client}>
    <div>
      <h2>My first Apollo app šŸš€</h2>
    </div>
  </ApolloProvider>
);

render(<App />, document.getElementById('root'));

šŸŽ Adding GraphQL Code Generator

Now, having set up the client is nice and all, but we want to write our queries only once and be able to generate all the code we'll need to run them. For this to work, we're going to install GraphQL Code Generator

$ yarn add -D @graphql-codegen/cli

and follow the instructions we're presented with in the next step

$ yarn graphql-codegen init

We'll select


? What type of application are you building?
āÆā—‰ Application built with React

? Where is your schema?:
<Enter your API endpoint in the next step>

? Where are your operations and fragments?:
src/graphql/**/*.graphql

? Pick plugins:
 ā—‰ TypeScript (required by other typescript plugins)
 ā—‰ TypeScript Operations (operations and fragments)
 ā—‰ TypeScript React Apollo (typed components and HOCs)
 ā—‰ Introspection Fragment Matcher (for Apollo Client)

? Where to write the output: (src/generated/graphql.tsx)
<Confirm>

? Do you want to generate an introspection file? (Y/n)
<Confirm>

? How to name the config file? (codegen.yml)
<Confirm>

? What script in package.json should run the codegen?
generate

Now that everything is set up, we can go ahead and create our first query! For our example, I've got a podcast project that I'm going to load episodes from, so I'll create the following query in src/graphql/queries/episodes.graphql

query loadEpisodes {
  episodes {
    id
    title
  }
}

We can run yarn generate to generate a really huge file containing everything we need to load podcast episodes.

āÆ yarn generate
$ graphql-codegen --config codegen.yml
  āœ” Parse configuration
  āœ” Generate outputs
āœØ  Done in 3.44s.

šŸ”— Hook Me Up!

We're almost there! Because we want to fetch our data using React hooks (the way it should be), we need to update our code generation config to reflect this:

overwrite: true
schema: '<Your GraphQL endpoint>'
documents: 'src/**/*.graphql'
generates:
  src/generated/graphql.tsx:
    plugins:
      - 'typescript'
      - 'typescript-operations'
      - 'typescript-react-apollo'
      - 'fragment-matcher'
    config:
      # we don't need regular React components
      # or HOCs, so we'll disable them for now
      withComponent: false
      withHOC: false
      # This is required to enable
      # the generation of React hooks
      withHooks: true

After running yarn generate once again, we're now able to import our generated hooks!

import { useLoadEpisodesQuery } from './generated/graphql';

const MyComponent = () => {
  const { data, loading, error } = useLoadEpisodesQuery();

  if (loading) {
    return <p>Loading</p>;
  }

  if (error) {
    return <p>Something went wrong: {error.message}</p>;
  }

  return (
    <ul>
      {data.episodes.map(e => (
        <li key={e.id}>{e.title}</li>
      ))}
    </ul>
  );
};

And that's it! We started by installing our GraphQL client and gradually added code generation, enabling us to write queries that turn into code. Now we're able to showcase our podcast episodes, add more data when we need it, and move quickly when we change anything.


Thanks for reading this short guide! If you've got any questions, suggestions, or feedback in general, don't hesitate to reach out on Twitter or by mail.