Patrick Desjardins Blog
Patrick Desjardins picture from a conference

How to consume GraphQL in TypeScript and React

Posted on: 2019-04-17

In this article I'll cover two different approach concerning rendering information coming from a GraphQL server in React while being strongly typed.

Approach 1: The normal fetch

The first approach is the one I prefer because it is not intrusive. It is very similar of to do a normal REST Ajax call. It can be swapped from an existing fetch command that is using not GraphQL without having to change much. The approach is frontend framework agnostic, meaning that you can use it outside React. Furthermore, this approach works well in a middleware if you are using Redux, but can be directly used in you custom "service" layer or when a component is mounted -- you choose.

The first step is to get some NPM packages. In this approach, I am using two packages related to GraphQL: the Apollo-boost and the graphql-tag.

import ApolloClient, { ApolloQueryResult } from "apollo-boost";
import { Proto } from "autogenerated/octoolstypes";
import gql from "graphql-tag";
import React from "react";

You then need to create an ApolloClient which is the library that will perform the query. See the ApolloClient as an HTTP request library, similar to Axios. It lets you specify the URL to perform the POST HTTP request, but also custom headers. For example, I am specifying a bearer token to have the request authenticated.

this.client = new ApolloClient({
    uri: "/api/graphql",
    headers: {
        authorization: `Bearer ${this.props.token}`
    }
});

The next step is to have the query executed. This is where you can swap your existing fetching code with the ApolloClient.

(async () => {
    try {
        const result: ApolloQueryResult<Proto.Query> = await this.client.query<Proto.Query>({
            query: gql`
                query Proto {
                    org(orgId:orgIdParam) {
                        name
                    }
                }
            `
        });
        if (result.data.org && result.data.org.name) {
             // Do something with result.data.org.name
        }
    } catch (error) {
        console.error(error.networkError.bodyText);
    }
})();

That's it. Very simple, easy to understand because it is similar to most fetching pattern. The ApolloQueryResult takes a generic type which is the format of the gql. It means that when building for the first time the query that you might not want to explicitly specify the type because it does not exist. As discussed in a previous article, there is tool that will scan the gql query and generate the type for you.

Approach 2: Strongly bound to React

The second approach is my less favorite. I favor the first one because I like separating my view from my logic. It is easier to unit test, and the separation of concern make the code easier to understand and refactor. Nonetheless, the option is available and worth exploring.

The second approach use an Apollo component that will wrap the application. It is similar to the React-Redux provider. It takes a single property which is the client, that is the same as provided in the first approach.

public render(): JSX.Element {
    return (
        <ApolloProvider client={this.client}>
            <ConnectedRouter history={history}>
                <AppRouted />
            </ConnectedRouter>
        </ApolloProvider>
    );
}

The difference is that because we have the client connected in the ApolloProvider that any React component underneath has access to the possibility of querying by creating a Query component.

<Query<Proto2.Query>
    query={gql`
        query Proto2 {
            org(orgId: orgIdParam {
                name
            }
        }
    `}
>
    {queryResult => {
        if (queryResult.loading) {
            return "Loading";
        }
        if (queryResult.error) {
            return "Error";
        }
        if (queryResult.data === undefined || queryResult.data.org === null) {
            return <p>None</p>;
        }

        return (
            <div>
                <h5>Name:</h5>
                <p>{queryResult.data.org.name}</p>
            </div>
        );
    }}
</Query>

Once again, the Query is strongly typed by using the gql defined in the query parameter of the query component. Until the type is generated, which mean that the gql query has been picked up by the script that build the TypeScript file, the query cannot be explicitly typed. However, once it done, any future change will catch on. This approach has the query executed every time the container of the Query component is rendered which mean that future optimization, like having a caching policy specified in the ApolloClient might be a good thing.

Wrap-up

There are more than two ways to bind GraphQL data into your React application while having the benefice of being strongly Typed. The first approach is more agnostic, the second embrace React with a component to handle a query. As long as you are comfortable, either does the job. I recommend using the former approach because it is flexible without having your fetching code dependent on React but otherwise, the end result of a strongly typed code is the same.

GraphQL Posts