One of the exciting things about GraphQL is its ability to build real-time applications using GraphQL subscriptions. In this tutorial, I’ll be showing you how Google Maps updates your location in real-time with GraphQL subscriptions & Apollo Client.
- Basic knowledge of Node.js and React.js
- A basic understanding of GraphQL concepts such as schema, query, mutation, etc.
What is GraphQL Subscription?
Subscriptions are a GraphQL feature that allows a server to send real-time data/updates to its GraphQL clients when a specific event happens. Subscriptions are usually implemented with WebSocket. In this setup, the server maintains a steady connection to its subscribed client. This also breaks the “Request-Response-Cycle” that was used for all previous interactions with the API.
Instead, the client initially opens up a long-lived connection to the server by sending a subscription query that specifies which event it is interested in. Every time this particular event happens, the server uses the connection to push the event data to the subscribed clients.
GraphQL subscriptions are based on a simple publish-subscribe system. The subscription query will re-run whenever some data changes are published. A common pattern will be to publish mutation results to a channel, so a subscription can send a new result to clients whenever a mutation happens. This is why some people call subscriptions the result of someone else’s mutation.
Subscription Server-Client Flow
Real-time vehicle tracking app
We’ll be building a simple vehicle tracking app. We’ll start by building the GraphQL server, then we’ll build a react.js app that will consume the GraphQL server.
Implementing GraphQL subscriptions
We are implementing GraphQL subscription through two packages, graphql-subscriptions and subscriptions-transport-ws. We want GraphQL clients to be notified when new-vehicle locations are added, so let's add a subscription schema with the root subscription operation type.
Next, we add the resolver for this operation and its root value, this root value is then added to the schema.
After adding schema changes we created the controller method getNewVehicle where we implemented pubsub from the graphql-subscriptions package for the actual subscription activity.
The subscribe property is mapped to a function that will return AsyncIterator, which is used by the GraphQL server to push the event data to the client. Now let us publish a subscription event when a new vehicle location is added.
The final step is to create a subscription server with the help of subscriptions-transport-ws package.
Building the frontend app
Now let us implement GraphQL Subscription in a React app with Apollo-Client. Let’s set up the Apollo plugin in App.js
Here, we create new instances of both HTTP link and WebSocketLink with the URLs (http://localhost:7000/graphql and ws://localhost:7000/subscriptions ) of our GraphQL server respectively. Since we can have two different types of operations (query/mutation and subscription). Then we pass the ApolloClient as a prop to the ApolloProvider and wrap all components that we would like to access, with the data that is managed by Apollo.
Let’s now look at how we implement the map feature in our application.
Here we are implementing an example of animate a car, moving through the road, as it reaches its destination. For this, we are using react-google-maps, which is a wrapper for the Google Maps library.
All we need for the map functionality is one query to retrieve all locations from the database.
We then subscribe for changes on the VehicleLocation type
We now define a subscribeToMore object, which contains our subscription. To update the location in realtime when a new location is added to the database.
Now, if we test it out, we should see our vehicle tracking in realtime.
In this tutorial, we have seen how to build realtime apps with GraphQL subscriptions. We started by first building a GraphQL server, then implemented a React app of vehicle tracking that consumes the GraphQL server. You can access the complete code of this tutorial on Github.