GraphQL Cache Updates Made Easy

Share on facebook
Share on google
Share on twitter
Share on linkedin

Apollo Graphql comes with built-in support for caching which can be used as a state management system (which they recommend). There are a couple of different ways to update cache after an update in this state management system:

  • Refetch query
  • Built-in normalization
  • Update callback

This post will teach you when and how to do the different kinds of cache update strategies and show you some util functions to make cache updates as easy as a one-liner.

Refetch query

After executing a mutation and changing something on the server, chances are you’re going to need to refresh the UI. And a quick solution is to use the refetchQueries API.

For example: With refreshQueries you specify one or more queries in order to refresh the parts that have been affected by the mutation.

For example:

While this works, it has a big disadvantage attached to it, in that we need to make multiple network trips to render our UI. This extra round trip also occurs even if we have the data on the client.

Built-in normalisation

The Apollo Client is an abstraction on top of normalized data and cache and this facade provides access to the underlying data. This is similar to how databases handle access to data. This storage facade can intercept queries and automatically remove duplication. It can also update the cache automatically, though this depends on the type of mutation.

When dealing with any type of data that needs to be stored somewhere, we need to keep the amount of duplicate data saved to an absolute minimum. Ideally, the goal here is no duplicate data.

This facade provides an API layer that is much easier to use. The API’s allow us to:

  • Configure/design the client-side data using cache policies.
  • Query data using client.readQuery or client.watchQuery.
  • Mutate data using useMutation.

The Apollo Client provides a set of tools to interact with the cached data and all of this comes out of the box and ready to use. By minimizing direct access to the actual data using the facade/API enables data normalization, behind the scenes.

How the Apollo Client normalises data is:

  • By splitting the results into individual objects.
  • Assign a logically unique identifier to each object, so the cache is able to keep track of the object.
  • Storing objects in a flattened structure.

You can learn more about how GraphQL does normalization here.

Update callback

When we perform an add, remove or reorder items that are cached, the Apollo Client is not able to automatically update the cache. We need to write an update function to instruct the cache on how we want to update it.

There are some rules that we can follow so we know when we need to create our own update function. These rules are as follows:

  • If the side-effect we want to occur has nothing to do with the return data.
  • We can’t return the entire set of changed objects.
  • The mutation changes the ordering.
  • The mutation adds or removes items.

A side-effect would be to clear the cache after a mutation, for example logging out of a system. We get a successful response from the mutation, but we don’t need to cache anything. For this we can use the client.clearStore() method in the update function.

We need to return the entire list of objects that were changed for the automatic update to work (using the normalization).

To update the cache if we cannot return the entire set, we use the update function:

To remove an item from the cache filter out the deleted item.

Notice how we first remove the entity from the query and then from the normalized cache using evict.

To add an item to the cache, get the existing entities from the readQuery and use the spread operator ([…]) to append the new course to the objects in cache.

Now we know what we need to do and how to do it, let’s see how we can make it simpler to do these cache updates.

Making Cache Updates Easy

As you saw in the previous section, doing the manual updates can be quite tedious. For that reason, I have created some utils for doing these updates as a one-liner.

First we define an interface with an id, as this is the convention we will be using to know the property to get the entity’s id from.

From here we can create a function to handle adding new items to the cache.

This will read the query and add the new entity to the cache.

And the same for deleting:

This will read the query and remove the entity from the cache.

These helpers can be used like this:

Conclusion

In this post, we learned about the various ways that the Apollo Client handles updates to the cache. We looked at how the Apollo Client handles automatic cache updates using normalization, refetch queries, and manual updates of the cahce.

We finished off by showing you how to simplify the manual update process by creating a function to handle the update and deletes, so these become an easy-to-use one line of code.

Do you want to become an Angular architect? Check out Angular Architect Accelerator.

Related Posts and Comments

New Angular project? This is how I would start

Throughout my career as an Angular consultant, I have had occasions where I had to start with an Angular project from scratch which is a pipe dream for every software developer. Do everything the right way at the get-go, no legacy, you follow me… So, how do you get started with the project from scratch,

Read More »

Error, loading, content…? Use this page pattern for your Angular apps

When developing Angular applications, it’s common for pages to transition through three key states: error, loading, and show content. Every time you fetch data from an API, your page will likely show a loading indicator first, and then either render the content successfully or display an error message if something goes wrong. This pattern is

Read More »

How to do Cypress component testing for Angular apps with MSW

In this post, we will cover how to do Cypress Component testing with MSW (mock service worker) and why it’s beneficial to have a mock environment with MSW. The mock environment My recommendation for most enterprise projects is to have a mocking environment as it serves the following purposes : * The front end can

Read More »

Handling Authentication with Supabase, Analog and tRPC

In this video, I cover how to handle authentication with Supabase, Analog and tRPC. It’s based on my Angular Global Summit talk about the SPARTAN stack you can find on my blog as well. Code snippets Create the auth client Do you want to become an Angular architect? Check out Angular Architect Accelerator.

Read More »

Leave a Comment

Your email address will not be published. Required fields are marked *