Freecom Tutorial: Realtime Updates with GraphQL Subscriptions (3/6)

Last updated 2 months ago

This is the third chapter of our tutorial series where we teach you how to build a fully-fledged Intercom clone using Graphcool and Apollo Client. In the last chapter, you learned how to develop the fundament for the app by configuring Apollo and setting up the required queries and mutations. Today is all about getting the realtime functionality into our app!⚡️

What are GraphQL Subscriptions?

Subscriptions are a GraphQL feature that allow you to get realtime updates from the database in a GraphQL backend. You set them up by subscribing to changes that are caused by specific mutations and then execute some code in your application to react to that change.

Using Apollo Client, you can benefit from the full power of subscriptions. Apollo implements subscriptions based on web sockets.

The simplest way to get started with a subscription is to specify a callback function where the modified data from the backend is provided as an argument. In a chat application you might be interested in any changes on the Message type. This can be either a new message has been sent, an existing message was modified or an existing message was deleted. The code for such a subscription could look as follows:

Note: This code assumes that you have configured and set up the ApolloClient and made it available in the props of your React component using withApollo, just like we saw in the previous chapter. We'll explain how to setup the ApolloClient for subscriptions in just a bit.

Figuring out the Mutation Type

The kind of change that happened in the database is reflected by the mutation field in the payload which contains either one of the three values:

  • CREATED: for a node that was added
  • UPDATED: for a node that was updated
  • DELETED: for a node that was deleted

Getting Information about the changed Node

The node field in the payload allows us to retrieve information about the modified data record. It is also possible to ask for the state that node had before the mutation. You can do so by including the previousValues field in the payload:

Now you could compare the fields in your code like so:

If you specify previousValues for a CREATED mutation, this field will just be null, this is logical because there were no previous values for that node because it was just created. Similarly, the node for a DELETED mutation will be null as well, but you can access the latest state of the deleted node through previousValues.

Also notice that node will give you access to values from related fields while previousValues can only access fields from the type itself. So for the Message mutation, it would be possible to access fields of the agent of a message:

Subscriptions with Apollo

Apollo uses the concept of an Observable (which you might be familiar with if you have worked with RxJS before) in order to deliver updates to your application.

Rather than using the updated data manually in a callback, you can benefit from further Apollo features that conveniently allow you to update the local ApolloStore which contains the cached data from previous queries.

Tutorial Workflow

We're hosting all the code for the tutorial on GitHub. Each chapter comes with two folders:

  1. freecom-0X: Contains the starter code for chapter X
  2. freecom-0X-final: Contains the final code for chapter X and serves as a reference solution if you get lost along the way

Each written chapter gives a high-level overview on the current topic. For step-by-step instructions watch the corresponding video.

Setting up the ApolloClient to use Subscriptions

To use subscriptions in your app, you need to configure the ApolloClient accordingly. This time, in addition to the GraphQL endpoint, we also need to provide a SubscriptionClient that handles the websocket connection between our app and the server.

To find out more about how the SubscriptionClient works, you can visit the repository where it's implemented. Let's now see how we can to setup the ApolloClient and prepare it for using subscriptions.

First, in order to use the SubscriptionClient in your application, you need to add it as a dependency:

Once you've installed the package, you can instantiate the SubscriptionClient as follows (adjusting the setup of the ApolloClient that we saw in the previous chapter):

Integrate Subscriptions for realtime Updates in the Chat

Considering the Chat component in Freecom, essentially only one query and one mutation are required to enable the Customer and the support Agent to have a Conversation where they can exchange messages:

Note: This code is slighlty simplified compared to the version we're using in the video series!

Let's now see how we can use a subscription to get the promised realtime updates in our code. As mentioned before, we need to subscribe to the allMessagesQuery:

Notice that we're using a different method to subscribe to the changes compared to the first example where we used subscribe directly on an instance of the ApolloClient. This time we're calling subscribeToMore on the allMessagesQuery, which is available in the props of our component because we wrapped it with graphql before.

Next to the actual subscription that we're passing as the document argument to subscribeToMore, we're also passing a function for the updateQuery parameter. This function follows the same principle as a Redux reducer and allows us to conveniently merge the changes that are delivered by the subscription into the local ApolloStore. It takes in the previousState which is the the former query result of our allMessagesQuery and the subscriptionData which contains the payload that we specified in our subscription. In the implementation, we then retrieve the new message by accessing the node property of the specified payload.

From the Apollo docs: subscribeToMore is a convenient way to update the result of a single query with a subscription. The updateQuery function passed to subscribeToMore runs every time a new subscription result arrives, and it's responsible for updating the query result.

Fantastic, this is all we need in order for our chat to update in real-time! 🚀 If you want to learn more about subscriptions, check out our example app or the documentation.

Wrap Up

In today's chapter, you learned how you can bring realtime functionality to your app using GraphQL subscriptions. Calling subscribeToMore on a query allows to subscribe to changes happening in the database and specify what information you want to receive upon every change. By further passing a reducer function for updateQueries to the same call, you can directly specify how the new data should get merged into the previous query results.

In the next chapter, we're going to enable support agents to join the chat by integrating serverless functions that we use to access the Slack API.

Let us know how you like the tutorial or ask any questions you might have. Contact us on Twitter or join our growing community on Slack!

Get a notification when we release a new chapter!