Realtime Updates with Subscriptions

The goal of this chapter is to add realtime functionality to the app using GraphQL subscriptions. In particular, you’re going to make sure that when other users vote on a link, the link’s vote count updates immediately in the app for all other users without the need to refresh the page.

What are GraphQL Subscriptions?

GraphQL subscriptions allow you to add event-based realtime functionality to your app. A client can subscribe to specific events that are happening on the server-side. Then, whenenever that event actually happens, the server will send the corresponding data over to the client.

Events usually refer to mutations, so typically we’re talking about events where data was created, updated or deleted.

Subscriptions are somewhat different from queries and mutations, since they don’t follow a request-response-cycle but instead represent a stream of data. The most common way to implement subscriptions is by using WebSockets, where the server maintains a steady connection to the subscribed clients that it uses to send over the data upon each event.

Subscriptions with Relay Modern

Subscription API

Subscription support was only added to Relay with the release of Relay Modern. Client can now use the requestSubscription function to initiate a subscription.

requestSubscription works very similar to the commitMutation function as it also allows you to implement an updater functions to specify how you want the cache to update based on the new data that was received from the server.

However, in order to get requestSubscription to work, you also need to configure your Relay Environment accordingly and provide the URL for your subscription endpoint. If subscriptions are implemented with WebSockets, the subscriptions URL will contain the wss protocol instead of http.

Using Subscriptions with Graphcool and Relay Modern

Graphcool generally exposes two different GraphQL APIs whose type definitions slitghly vary:

  • Simple API: Intuitive API to provide CRUD-style capabilities for all model types
  • Relay API: Adheres to the requirements that Relay has for a GraphQL schema

Currently, subscriptions are only supported for the Simple API. However, you can still use subscriptions with the Relay API by making some manual adjustments to the schema.graphql which you feed into the relay-compiler.

Notice that we already did these manual adjustments for you and you already have them in your project as you imported the project from this URL in chapter 3. If you’re interested in what these changes actually look like, take a look at the Subscription type in schema.graphql.

Configuring the Relay Environment

The first thing you need to do to get subscriptions to work is add websocket support to your project.

Note: We’re using a version 0.8.3 of the subscriptions-transport-ws package to be able to use the SubscriptionClient. The tutorial will soon be updated to use the latest APIs.

This package contains the SubscriptionClient that you need to setup subscriptions on the frontend. The SubscriptionClient is a good fit in this case as it implements the same protocol as the subscriptions API from Graphcool.

Next you’ll have to configure your Relay Environment and tell it about the additional endpoint that you want to use for subscriptions. The way how this works is actually by adding a second function to the creation of the Network. This function knows about the subscription endpoint and is able to initiate and maintain a connection to it.

Let’s quickly understand what’s going on there:

  1. Instead of passing a closure directly into Network.create(), you just pull out the code of that closure and store it in a variable called fetchQuery. Note that you’ll have to replace __PROJECT_ID__ again with your actual project ID.
  2. Here you define the second function called setupSubscription that the Network needs in order to be able to talk to the subscriptions endpoint. You’re using the SubscriptionClient in that function to initiate and maintain a connection to the given endpoint. The config that’s passed into the function carries the subscription query which determines what event the client wants to subscribe to and what data it wants to receive. Note that again you need to replace the placeholder for __PROJECT_ID__ with the actual ID of your Graphcool project. Also, you need to replace the placeholder for __REGION__ with the AWS region that your graphcool API endpoint is served from.
  3. Finally, we take fetchQuery (which is the same code as before but stored in a variable) and setupSubscription and use them to create the Network, which then will be used to instantiate the Relay Environment.

If you’re not sure what your Graphcool project ID is that you need to replace the __PROJECT_ID__, you can open project.graphcool and check its frontmatter or execute graphcool endpoints in a terminal to see the endpoints for the Relay API and Subscriptions API.

To find the __REGION__ your endpoint is served from, go to your Graphcool console. Click the Endpoints-button in the bottom-left corner, go to Subscriptions API and replace __REGION__ with the region mentioned there (example: ‘wss://subscriptions.ap-northeast-1.graph.cool/v1/PROJECT_ID‘)

Awesome, your app is now capable of using subscriptions! ⚡️

Creating the Subscription

Similar to what you did with the mutations before, you’ll implement each subscription in a dedicated file to provide a more convenient wrapper around the requestSubscription function that’s provided by Relay.

Let’s take a closer look at the subscription query that you’re storing in newVoteSubscription first:

  1. The root field of the subscription and the belonging filter express the event that you’re interested in. Here, you specify that you are interested all events that are happening on the Vote type.
  2. In the payload of the subscription query, you’re then including information about the new Vote that was created, this information is represented by the node field. Every time a vote is submitted by another user, the server will send information about that new vote, including the id of the user who created it and the total number of votes on the corresponding link (link._votesMeta).
  3. Finally, this part is similar to what you already did for the mutations: You’re exporting a function that can be called from anywhere in the application and which actually submits the subscription to the server by wrapping the requestSubscription function. Notice that you’re using the updater to increase the number of votes for the link that was voted on.

Initiating the Subscription

Now that you have all required infrastructure setup, you can go ahead and actually iniate a subscription! For our project, it’s not too important where exactly the subscription is invoked as there are no context-dependent arguments that the subscription needs. However, it is important that the subscription only gets invoked once, so you don’t want to put it into the Link component where it would be invoked as many times as Link elements are rendered. You’ll therefore put it into the LinkList component.

Then of course you also need to add the corresponding import.

Before you’re running the app, you’ll need to invoke the Relay Compiler again so it can compile the graphql-tagged code inside NewVoteSubscription.js.

All right, you can now run the app with yarn start to test your subscription. The best way to test subscriptions is to use two different windows (or simply tabs) that are both running the app. If you then submit a vote in one window, the app should automatically update in the second window as well. 🎉

Run the app with yarn start

Unlock the next chapter
What's the name of the function that Relay provides to initiate a subscription with the server?
subscribe
createSubscription
requestSubscription
createRealtimeConnection