This section is all about bringing realtime functionality into the app by using 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.
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:
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.
// ...
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! ⚡️
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.