Easing the pain of using GraphQL with a React Typescript frontend
Tags: react, graphql, codequality
Published: 2019-10-02 09:11:10


Serving the data for your app from GraphQL has so many benefits, a single endpoint to hit, not oversubscribing to data, to name a few. But when you couple this with a Typescript project the markup can get a little confusing and messy.

Having to write and provide types for all parts of your GraphQL queries and mutations can muddy your code. But because the schema is known ahead of time we can generate the Typescript types programmatically. This saves so much time and allows us to quickly write Typed GraphQL, React apps.

There are a number of packages that do just this but my favourite one at the moment is [GraphQL code generator](https://graphql-code-generator.com/). It provides a simple to use CLI tool and also gives you the option to not only generate the types but also typed query and mutation components. These can then be imported. This really cleans up your code, making it much easier to read.

## Setting up

To keep this article a reasonable length, I am assuming that you already have a React Typescript UI and a backend serving data over a GraphQL API.

First, we need to install the code generator:

```bash
yarn add -D @graphql-codegen/cli

# Once installed
graphql-codegen init
```

`graphql-codegen init` will now run through a load of questions. This process will guide you through setting up your schema, selecting and installing plugins and choosing where to put all those sweet, sweet generated files!

![Money](https://media.giphy.com/media/9GLiEBLM0qiSQ/giphy.gif)

Because we are writing our project in Typescript, make sure you add the necessary Typescript plugins. It will also add a `generate` script to your `package.json` file so you can easily regenerate your files.

The result of the init function is a `config.yml` file that will look something like this:

```yml
schema: http://localhost:3000/graphql
generates:
  ./src/types.d.ts:
    plugins:
      - typescript
    config:
      withHooks: true
```

There is a lot that can be [configured](https://graphql-code-generator.com/docs/getting-started/codegen-config) but the init function is enough to get you started.

When you are ready run `npm run generate` to generate all your types and components. `graphql-codegen` will read your queries, mutations and subscriptions and generate the required files for you. You should now have a **generated** folder in your project. You could name this folder anything you want to but I recommend keeping it as generated. This keeps it clear not to edit files in this folder as any changes will be over-written when you run generate again.

## Connecting to your API

I use Apollo to connect to my backend for most of my projects and so we will do the same.

Let's install the packages needed to use Apollo as our GraphQL client

```bash
yarn add apollo-boost apollo-cache-inmemory graphql-tag graphql react-apollo apollo-link-http
```

Now let's edit our `index.tsx` file to use Apollo

```typescript
import ApolloClient from "apollo-boost";
import { InMemoryCache } from "apollo-cache-inmemory";
import React from "react";
import { ApolloProvider } from "react-apollo";
import ReactDOM from "react-dom";
import AppRouter from "./components/Router/Router";
import { HttpLink } from "apollo-link-http";

const link = new HttpLink({ uri: "https://example.com/graphql" });

const cache = new InMemoryCache({});

const client = new ApolloClient({
  link,
  cache
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <AppRouter history={history} browser={browser} />
  </ApolloProvider>,
  document.getElementById("root")
);
```

With that all set up we can now start accessing our data. `graphql-codegen` gives us the open to generate *render props*, *HOC* and *hooks* based code. This depends on how you have it configured. There are examples of render props and hooks below. I personally would choose hooks every day. It is so much neater.

```typescript

// Render props example
import * as React from "react";
import { IconsLayer, QueryLoading } from ".";
import { GetEventsQueryComponent } from "../generated/apolloComponents";

interface IconsLayerProps {
  [...]
}

export const EventsSitesIcons: React.FC<IconsLayerProps> = React.memo(props => {
  return (
    <GetEventsQueryComponent
      variables={{ date: moment().format("YYYY-MM-DD") }}>
      {({ data, loading, error }) => {
        if (loading) return <QueryLoading />;
        if (error) return <p>Error....</p>;

        if (data && data.nodeQuery) {
          return (
            <IconsLayer
              [...]
            />
          );
        }
        return null;
      }}
    </GetEventsQueryComponent>
  );
});

// Hooks example
import * as React from "react";
import { IconsLayer, QueryLoading } from ".";
import { useEventsHook } from "../generated/apolloComponents";

interface IconsLayerProps {
  [...]
}

export const EventsSitesIcons: React.FC<IconsLayerProps> = React.memo(props => {
  const {data, loading, error} = useEventsHook();

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

        if (data && data.nodeQuery) {
          return (
            <IconsLayer
              [...]
            />
          );
        }
        return null;
  )
});
```

The `GetEventsQueryComponent` component and hooks examples are typed but it's clean to implement because the adding of types is abstracted away. The component has all the benefits of Typescript (like Intellisense) but without being cluttered and hard to read. Obviously you could do the same yourself with `graphql-codegen` but this is programmatic, faster and less error-prone.

Now every time, you add or refactor any of your GraphQL queries, mutations or subscriptions, make sure you run the generator and watch with amazement as your types and components are generated for you. MAGIC!

![Magic](https://media.giphy.com/media/6eoaTzUiNV8Xe/giphy.gif)

## Conclusion

Using a code generator seems like a no-brainer to me. It allows me to get all the benefits of from using Typescript in all of my GraphQL code too.