GraphQL on the client side with Apollo, React, and TypeScript

JavaScript React

Recently, we’ve developed a GraphQL API in our NestJS series. NestJS under the hood uses Apollo Server. Although it is compatible with any GraphQL client, the Apollo platform also includes the Apollo Client.

If you want to know more about GraphQL and how to develop a backend with it, check out API with NestJS #27. Introduction to GraphQL. Queries, mutations, and authentication

This article aims to be an introduction to the Apollo Client. It gives an overview of its features while providing examples with TypeScript.

The most fundamental function of the Apollo Client is making requests to our GraphQL API. It is crucial to understand that it has quite a lot of features built on top of it.

Why you might not need it

An important thing about the Apollo Client is that it is more than just a tool for requesting data. At its core, it is a state management library. It fetches information and takes care of caching,  handling errors, and establishing WebSocket connections with GraphQL subscriptions.

If you are adding GraphQL to an existing project, there is a good chance that you are already using Redux, Mobx, or React Context. Those libraries are commonly used to manage the fetched data. If you want to keep them as your single source of truth, you would not want to use Apollo Client.

Consider using a library like graphql-request if the only thing you need is to call your GraphQL API and put the response in your state management library.

Introducing the Apollo Client with TypeScript

Above, you can see me using a  variable. In this article, we use Create React App with TypeScript. It creates a file for us. Let’s use it to define our variable.

We need to remember that weh Create React App, our environment variables need to have the prefix.

react-app-env.d.ts

Now, we need to add our variable into the file.

Validating your environment variables with a library such as envalid seems like a good idea also.

Setting up the Apollo Client

The first step in setting up the Apollo Client is installing the necessary libraries.

Fortunately, they already contain the TypeScript declaration. We can see that on the NPM page:

TypeScript declarations

The second step is creating an instance of the . This is where we need our environment variable.

apolloClient.tsx

There are slight differences in the TypeScript syntax between the and . Therefore, I tend to stick to the file extension to keep my code consistent.

One of the features of the Apollo Client is caching. Above, we are initializing the . It keeps the cache in memory that disappears when we refresh the page. Even though that’s the case, we can persist it using Web Storage by using the apollo3-cache-persist library.

The last part of setting up the Apollo Client is connecting it to React. To do so, we need the that works similarly to built into React.

app.tsx

Performing queries

Once all of the above is ready, we can start using our GraphQL API. The most basic functionality of the Apollo Client is querying data.

In our NestJS course, we create an API for managing posts. Let’s now create a component that can display a list of them. Since we are using TypeScript, the first step would be creating a interface.

post.tsx

To perform a query, we first need to pass it into the tagged template. Its job is to parse the query string into a query document. Then, we need to pass it to the hook.

If you want to know more about tagged templates in general, check out Concatenating strings with template literals. Tagged templates

app.tsx

Since there are quite many things going on both with the query and the TypeScrip definitions, I suggest creating a separate custom hook for that. It would also make it quite easy to mock for testing purposes.

I tend to create quite a lot of custom hooks to keep the code clean and readable. If you want to know more about it, check out JavaScript design patterns #3. The Facade pattern and applying it to React Hooks

The hook returns quite a few things. The most essential of them are:

  • – contains the result of the query (might be ),
  • – indicates whether the request is currently pending,
  • – contains errors that happened when performing the query.
PostsList/index.tsx

The cache mechanism

A significant thing to notice is that the hook is called every time the renders. Fortunately, the Apollo Client caches the results locally.

The 29th part of the NestJS course mentions polling. It is an approach that involves executing a query periodically at a specified interval.

We specify the   in milliseconds.

Another approach to refreshing the cache is refetching. Instead of using a fixed interval, we can refresh the cache by calling a function.

PostsList/index.tsx

Mutating data

The second core functionality in GraphQL after querying data is performing mutations. Let’s create a custom hook for creating posts.

useCreatePostMutation.tsx

The hook also returns an array with two elements

  • the function that triggers the mutation; it returns a promise that resolves to the mutation result,
  • the result of the mutation with properties such as , , and .

With that knowledge, let’s create a simple form that allows us to perform the above mutation.

useCreatePostFormData.tsx

Above, we use the hook. As we’ve noted before, it returns an array where the first element is a function that triggers the mutation.

All that’s left is to use the hook with a form.

PostForm/index.tsx

Authenticating with cookies

In our NestJS course, we authenticate by sending the Set-Cookie header with a cookie and the flag. This means that the browser needs to attach the cookies because JavaScript can’t access them.

If you are interested in the implementation details of the above authentication, check out API with NestJS #3. Authenticating users with bcrypt, Passport, JWT, and cookies

To achieve this, we might need to modify our slightly.

Apollo Client has support for communicating with GraphQL servers using HTTP. By default, it sends the cookies only if the API is in the same origin. Fortunately, we can easily customize it:

With the option, Apollo Client sends the cookies even for cross-origin calls.

If you want to read more about the parameter, check out the MDN documentation.

Updating the cache after the mutation

The last piece missing is updating the list after the successful mutation. One of the ways to do so is to pass the parameter when calling the hook.

With it, we can directly access both the cache and the mutation result. By calling we get the cache’s current state, and with , we overwrite it.

useCreatePostMutation.tsx

Another good way of keeping our application up to date is through subscriptions. It deserves a separate article, though.

Summary

Today, we’ve looked into the Apollo Client and learned its basics. We’ve also considered if we need it in the first place because it might not be the best approach for some use-cases.

Looking into the fundamentals of the Apollo Client included both the queries and mutations. We’ve also touched on the subject of cookie-based authentication. There is still quite a lot to cover, so stay tuned!

Subscribe
Notify of
guest
3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ronaldo
Ronaldo
3 years ago

Nice article. Thanks a lot.

Olli
Olli
3 years ago

Hello! Thanks for this great articel!
Where can i find the separate “subscriptions” articel?