Realtime Updates with GraphQL Subscriptions

This section is all about bringing realtime functionality into the app by using GraphQL subscriptions.

What are GraphQL Subscriptions?

Subscriptions are a GraphQL feature allowing the server to send data to its clients when a specific event happens. Subscriptions are usually implemented with WebSockets, where the server holds a steady connection to the client. This means when working with subscriptions, we’re breaking the Request-Response cycle that is typically used for interactions with the API. Instead, the client now initiates a steady connection with the server by specifying which event it is interested in. Every time this particular event then happens, the server uses the connection to push the expected data to the client.

Subscriptions with Apollo

When using Apollo, we need to configure our ApolloClient with information about the subscriptions endpoint. This is done by adding another ApolloLink to the Apollo middleware chain. This time, it’s the WebSocketLink from the @apollo/client/link/ws package.

To get started, add subscriptions-transport-ws as a dependency to the app.

Next, let’s make sure our ApolloClient instance knows about the subscription server.

We’re instantiating a WebSocketLink that knows about the subscriptions endpoint. The subscriptions endpoint in this case is similar to the HTTP endpoint, except that it uses the ws (WebSocket) protocol instead of http. Notice that we’re also authenticating the WebSocket connection with the user’s token that we retrieve from localStorage.

split is used to “route” a request to a specific middleware link. It takes three arguments, the first one is a test function which returns a boolean. The remaining two arguments are again of type ApolloLink. If test returns true, the request will be forwarded to the link passed as the second argument. If false, to the third one.

In our case, the test function is checking whether the requested operation is a subscription. If it is, it will be forwarded to the wsLink, otherwise (if it’s a query or mutation), the authLink.concat(httpLink) will take care of it:

Apollo Link
Picture taken from Apollo Link: The modular GraphQL network stack by Evans Hauser

Subscribing to New links

For the app to update in realtime when new links are created, we need to subscribe to events that are happening on the Link type. We’ll implement the subscription in the LinkList component since that’s where all the links are rendered.

The subscribeToMore function takes a single object as an argument. This object requires configuration for how to listen for and respond to a subscription.

At the very least, we need to pass a subscription document to the document key in this object. This is a GraphQL document where we define our subscription.

We can also pass a field called updateQuery which can be used to update the cache, much like we would do in a mutation.

Let’s get started by providing the complete configuration we need for subscribeToMore to function properly.

.../hackernews-react-apollo/src/components/LinkList.js
// ...

subscribeToMore({
  document: NEW_LINKS_SUBSCRIPTION,
  updateQuery: (prev, { subscriptionData }) => {
    if (!subscriptionData.data) return prev;
    const newLink = subscriptionData.data.newLink;
    const exists = prev.feed.links.find(
      ({ id }) => id === newLink.id
    );
    if (exists) return prev;

    return Object.assign({}, prev, {
      feed: {
        links: [newLink, ...prev.feed.links],
        count: prev.feed.links.length + 1,
        __typename: prev.feed.__typename
      }
    });
  }
});

The definition of updateQuery is somewhat similar to that of update defined in Login.js and CreateLink.js.

The NEW_LINKS_SUBSCRIPTION will use the subscription operation of the GraphQL server to listen for any newly created links.

Now we can test our implementation by opening two browser windows. In the first window, we have our application running on http://localhost:3000/. In the second window, we can open the GraphQL Playground running in http://localhost:4000/ and send a post mutation. Here is an example mutation you can try:

mutation {
  post(url: "www.graphqlweekly.com", description: "A weekly newsletter about GraphQL") {
    id
  }
}

When you send the mutation, you should see the app update in realtime! ⚡️

Subscribing to New Votes

We can also subscribe to new votes that are submitted by other users so that the latest vote count is always visible in the app.

Similar to what we did before, we’re calling subscribeToMore but now using NEW_VOTES_SUBSCRIPTION as the document. This time, we’re passing in a subscription that asks for newly created votes. When the subscription fires, Apollo Client automatically updates the link that was voted on.

Fantastic! Our app is now ready for realtime and will immediately update links and votes whenever they’re created by other users.

Note: If you want to learn more about how subscriptions are implemented in the GraphQL server, check out the subscriptions chapter of the Node tutorial.

Unlock the next chapter
What transport does Apollo use to implement subscriptions?
WebSockets
TCP
UDP
HTTP 2