4 MIN READ
   //   Mar 24, 2021

How to build a real-time tracking app with GraphQL Subscriptions & Apollo Client

Archana Agivale

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.

Prerequisites

  • 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.

Using Apollo Client (a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL), you can unlock the power of subscriptions. Apollo implements subscriptions based on web sockets.

Publish-subscribe (PUB-SUB)

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

GraphQL subscriptions & Apollo Client real-time tracking app

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.

type Subscription {
newVehicleLocation: VehicleLocation!
}

Next, we add the resolver for this operation and its root value, this root value is then added to the schema.

root={      
newVehicleLocation:VehicleController.getNewVehicle
}

After adding schema changes we created the controller method getNewVehicle where we implemented pubsub from the graphql-subscriptions package for the actual subscription activity.

const { PubSub } = require('graphql-subscriptions');
  const pubsub = new PubSub();
public getNewVehicle(){
      return pubsub.asyncIterator("Vehicle_TOPIC")
  }

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.

pubsub.publish("Vehicle_TOPIC", {newVehicleLocation:data});

The final step is to create a subscription server with the help of subscriptions-transport-ws package.

const {  execute, subscribe } = require('graphql');
  import * as cors from 'cors';
  const { SubscriptionServer } = require('subscriptions-transport-ws');
/*... add graphql server creation code …*/
  SubscriptionServer.create({
               schema, 
               rootValue:root,
               execute, 
               subscribe 
           }, 
           {
               server // Listen WebSocket events on the raw server          
            });

Testing Subscription

GraphQL subscriptions & Apollo Client real-time tracking app

GraphQL subscriptions & Apollo Client real-time tracking app

GraphQL subscriptions & Apollo Client real-time tracking app

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

const httpLink = new HttpLink({ uri: 'http://localhost:7000/graphql'});
    const wsLink = new WebSocketLink({
                                     uri: 'ws://localhost:7000/subscriptions',
                                     options: {reconnect: true},
                             });
    const link = split(({ query }) => {
        const { kind, operation } = getMainDefinition(query);
        return kind === 'OperationDefinition' && operation === 'subscription';
       },
      wsLink,
      httpLink,
    );
    const cache = new InMemoryCache();
    const client = new ApolloClient({ link, cache });
    const App = () => (
             <ApolloProvider client={client}>
                 <div>
                     <Map />
                 </div>
        </ApolloProvider>
    );
export default App;

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.

query = gql`
   {
     VehicleLocation{
          id lat lng
      }
    }`;

We then subscribe for changes on the VehicleLocation type

subscription = gql`
   subscription{
    newVehicleLocation{
      lat lng
    }}

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.

<Query query={this.query}>
        {({ loading, error, data, subscribeToMore }) => {
          if (loading) return <p>Loading...</p>;
          const more = () => subscribeToMore({
            document: this.subscription,
            updateQuery: (prev, { subscriptionData }) => {
              if (!subscriptionData.data) return prev;
              const { newVehicleLocation } = subscriptionData.data;
              let oldPath = this.state.path;
              oldPath.push(newVehicleLocation);
              this.setState({ path: [...oldPath] })
            },
          });
          return <MapView path={this.state.path} subscribeToMore={more} />;
        }}
      </Query>

Now, if we test it out, we should see our vehicle tracking in realtime.

Conclusion

 

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.

Start your Digital

Transformation journey

Consultancy | Design | Drupal