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
ApolloClientand made it available in the
propsof your React component using
withApollo, just like we saw in the previous chapter. We'll explain how to setup the
ApolloClientfor 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
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
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.
We're hosting all the code for the tutorial on GitHub. Each chapter comes with two folders:
freecom-0X: Contains the starter code for chapter
freecom-0X-final: Contains the final code for chapter
Xand 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 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
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
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:
subscribeToMoreis a convenient way to update the result of a single query with a subscription. The
updateQueryfunction passed to
subscribeToMoreruns every time a new subscription result arrives, and it's responsible for updating the query result.
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.