GraphQL

Realtime Updates In GraphQL Apollo Server using Subscriptions

January 26, 2018

author:

Realtime Updates In GraphQL Apollo Server using Subscriptions

Most of the times, users get updated data on browser reloads. This drastically affects the user experience (UX). Users often expect to see the updated data instantly without any intervention. This is what realtime applications intend to do. We can achieve this with our GraphQL API using what is called subscriptions.

This is probably one of the most important features of GraphQL. GraphQL Subscriptions push the data from server to the clients who intends to listen to the real time updates from the server. They have similar syntax to query and send response to the subscribed client each time a dataset is published.

# What’s cooking?

We have set the stage and implemented CRUD queries and mutations and built a simple application using Express Server and Apollo in the past. We will take that API forward and integrate subscriptions to it. We will define various subscriptions that will notify clients each time a user inserts, updates or deletes a company.

And later, we will also build a react app to implement GraphQL subscriptions. For now, let us start working on our Company API. You can also clone the github repo for reference.

# Define Subscriptions

We can add subscriptions in the schema in same way as we did for queries and mutations.

# src/schema.js
...
const typeDefs = `
    ...
    type Mutation {
      ...
    }
    type Subscription {
      companyAdded: Company,
      companyEdited: Company,
      companyDeleted: Company
    }
    `;
...

Here we defining a root subscription type for insert, update and delete operation. It will return a Company type.

# GraphQL Apollo Subscription Resolver with WebSocket

Realtime client-server usually involves web sockets in javaScript. But don’t worry we won’t have to build a web socket now! We will utilize third party library subscriptions-transport-ws for it.

For now, we need to create a PubSub environment in our API where server can publish event and clients can subscribe to those events. graphql-subscriptions can help us build this environment. So let us first install both of these packages:

npm install subscriptions-transport-ws graphql-subscriptions --save

graphql-subscriptions has similar implementation to redux. Redux has typical reducers and actions. We can follow that pattern but since we need only one subscription, we will not get into complexity.

# src/resolvers.js
import { PubSub } from 'graphql-subscriptions';
...
const ADD_COMPANY = 'addCompany';
const EDIT_COMPANY = 'editCompany';
const DELETE_COMPANY = 'deleteCompany';
const pubsub = new PubSub();

We just imported PubSub from graphql-subscriptions and instantiated it. We also define a redux type equivalent addCompany,  editCompany and deleteCompanywhich are kind of event name.

# src/resolvers.js
...
const resolvers = {
    Query: {
        ...
    },
    Mutation: {
        addCompany: (root, { name }) => {
            ...
            pubsub.publish(ADD_COMPANY, { companyAdded: newCo });
            return newCo;
        },
        updateCompany: (root, { id, name }) => {
            ...
            pubsub.publish(EDIT_COMPANY, { companyEdited: updateCo });
            return updateCo;
        },
        deleteCompany: (root, { id }) => {
            ...
            pubsub.publish(DELETE_COMPANY, { companyDeleted: deleteCo });
            return deleteCo;
        },
    }
};

module.exports = resolvers;

In all our mutations, we are publishing an event for client to listen with the help of pubsub. The companyAdded and others come from the schema we declared earlier.

# src/resolvers.js
...
const resolvers = {
    Query: {
        ...
    },
    Mutation: {
        ...
    },
    Subscription: {
        companyAdded: {
            subscribe: () => pubsub.asyncIterator(ADD_COMPANY)
        },
        companyEdited: {
            subscribe: () => pubsub.asyncIterator(EDIT_COMPANY)
        },
        companyDeleted: {
            subscribe: () => pubsub.asyncIterator(DELETE_COMPANY)
        }
    }
};
...

And finally, we are defining a subscriptions which returns asyncIterator that emits realtime events to the clients.

# The GraphQL Apollo Subscription Server

The final step is to map GraphQL subscriptions to the server so that it can emit relevant events and notify client about it. As discussed, we will use subscriptions-transport-ws websocket server. Let us go ahead and implement it in server.js

# server.js
...
import { execute, subscribe } from 'graphql';
import { createServer } from 'http';
import { SubscriptionServer } from 'subscriptions-transport-ws';
...

As you can see, we just imported relevant components from the libraries.

const app = express();
const ws = createServer(app);
...
app.use('/graphql', bodyParser.json(), graphqlExpress({
    schema
}));

app.use('/graphiql', graphiqlExpress({
    endpointURL: '/graphql',
    subscriptionsEndpoint: `ws://localhost:${PORT}/subscriptions`
}));

Above, we are wrapping the express server within createServer. This typically opens a WebSocket connection where we then listen to any GraphQL subscriptions. We configure GraphiQL to listen to subscriptions.

ws.listen(PORT, () => {
    console.log('GraphQL API Server up and running at localhost:' + PORT);
    new SubscriptionServer({
        execute,
        subscribe,
        schema
    }, {
        server: ws,
        path: '/subscriptions',
    });
});

We can also initiate a new SubscriptionServer to handle subscriptions and thus we can start testing them immediately.

# Testing GraphQL API for Realtime Updates

The moment you’ve been waiting for after some serious coding! You can test the following subscription:

subscription NewCompanySub{
  companyAdded {
    id
    name
  }
}
http://localhost:8080/graphiql
GraphQL Apollo API Subscriptions

To test whether we receive instant data or not, open the http://localhost:8080/graphiql in new browser tab side by side. You can test CRUD operation here. For instance, the create operation:

mutation AddNewCo {
  addCompany (name: "HP"){
    name
  }
}

Here’s the result:

Realtime Updates In GraphQL Apollo Server using Subscriptions

Conclusion:

In this tutorial, we took the GraphQL API forward and integrated subscriptions to it. It enables realtime updates. We also tested the API in GraphiQL and thus completed the application.

Questions & Comments:

Hope you enjoyed the tutorial. If you face any issues or have any questions/suggestion, don’t hesitate to share in comment section below.

Leave a comment

Your email address will not be published. Required fields are marked *