Modern applications are increasingly becoming real time. Some examples of real-time updates in web apps include notification updates, chat messaging applications, and financial market updates. GraphQL makes creating apps with low latency, real-time updates easy with a feature called subscriptions.
In this guide, you will learn how to subscribe to real-time updates from a GraphQL server using subscriptions. A previous guide, How to Set Up GraphQL in a React App, covered how to set up a new React Project with GraphQL using Apollo Client. This guide builds on what you learned there. Here, you will learn how to keep your client in sync with the backend by setting up a connection to allow your server to proactively push updates as they occur.
One of the advantages of GraphQL is its strongly typed schema. This means you can see at a glance what resources are queryable and mutable. If the GraphQL backend supports it, this schema also includes information about subscriptions, which are a separate root type. If you imagined Apollo's GraphQL ExchangeRate sandbox with subscription support, then the schema would look like the snippet below:
1type ExchangeRate {
2 currency: String
3 rate: String
4 name: String
5}
6
7type Query {
8 rates(currency: String!): [ExchangeRate]
9}
10
11type Subscription {
12 ratesUpdated(currency: String!): ExchangeRate
13}
A root type called Subscription
is present. This is a special optional type.
It can have one or many fields.
In this case, ratesUpdated
is a field that clients can subscribe to by passing in a currency; every time that currency is updated on the server, a message is pushed to clients that are listening.
To subscribe to updates, use web-sockets rather than HTTP. The IETF Standards Documentation describes the motivation for using web sockets over HTTP. The advantage of web sockets is a lower overhead transport protocol compared to HTTP. This is useful when your server has frequent small updates.
In order to support web-sockets in your React application using GraphQL, you need to install a package:
1yarn add subscriptions-transport-ws
Then update your src/ApolloClient/client.js
file to:
1import { ApolloClient, ApolloLink, InMemoryCache, split } from "@apollo/client";
2import { HttpLink } from "apollo-link-http";
3import { WebSocketLink } from '@apollo/client/link/ws';
4
5const httpLink = new HttpLink({
6 uri: "https://48p1r2roz4.sse.codesandbox.io",
7});
8
9const wsLink = new WebSocketLink({
10 uri: "ws://48p1r2roz4.sse.codesandbox.io",
11 options: {
12 reconnect: true
13 }
14});
15
16const splitLink = split(
17 ({ query }) => {
18 const definition = getMainDefinition(query);
19 return (
20 definition.kind === 'OperationDefinition' &&
21 definition.operation === 'subscription'
22 );
23 },
24 wsLink,
25 httpLink,
26);
27
28export const client = new ApolloClient({
29 cache: new InMemoryCache(),
30 link: ApolloLink.from([splitLink]),
31});
You have updated the link
option, which customizes the flow of data from your graphQL operations to your backend.
In this case, use the split operation to combine two links.
When a mutation or query is made, then HTTP is used as the transport method.
If a subscription operation is requested, you instruct ApolloClient
to use web-sockets instead.
Now that you have the right packages and link
configured correctly, you can start subscribing to data updates in your backend.
The below code snippet demonstrates a simple React component subscribing to currency rate changes.
1import React from "react";
2import { useQuery, gql, useSubscription } from "@apollo/client";
3
4const RATES_UPDATED = gql`
5 subscription OnRatesUpdated($currency: string!) {
6 ratesUpdated(postID: $currency) {
7 currency
8 rate
9 name
10 }
11 }
12`;
13
14const LatestRates = ({ currency }) => {
15 const { data: { ratesUpdated }, loading } = useSubscription(
16 RATES_UPDATED,
17 { variables: { currency } }
18 );
19 return <h4>New rates: {!loading && ratesUpdated.rate}</h4>;
20};
21
22export default LatestRates;
Notice that the code is very similar to a component with a graphQL query. There are only minor differences:
useQuery
hook, you used the useSubscription
hook.loading
, data
, and error
in the same way the useQuery
hook does.Subscriptions are an extra tool that make your app respond in real time to backend data changes. This guide has demonstrated how to using graphQL subscriptions in a React app. You can further build on these skills by reading about the subscribeToMore function. This function= allows you to combine making an initial query and using a subscription to listen for incremental updates.