Realtime GraphQL Subscriptions with NodeJS & Express

In this article we are going to add realtime functionality to nodejs server with graphql subscriptions

Let’s begin with cloning the git repo and installing the necessary dependencies.

I’ve assumed that you have MongoDB already installed and running. By default it runs on the27017 port so we will use the same port for our app.

As an interactive in-browser GraphQL IDE we are going to use Playground brought to you by our pals from Graphcool. It provides automatic schema reloading and better support for GraphQL Subscriptions, which is critical in our case.

So let’s start our server.
yarn start

When you navigate your browser to http://localhost:8080/playground, you should enter the Playground:

But before playing with it, let’s highlight what we need to set up a GraphQL server with subscriptions.
. . .

Add subscriptions support to our GraphQL server through WebSockets

Since we can’t push frequent updates from the server to the client over HTTP, we need a WebSocket server. To create it we’re going to use the subscriptions-transport-ws package, which makes this quite simple. Add the necessary import statements in src/index.js
import { createServer } from 'http'; import { execute, subscribe } from 'graphql'; import { SubscriptionServer } from 'subscriptions-transport-ws';

To open WebSocket on the GraphQL server, we have to wrap the Express server with createServer.
const app = express(); const server = createServer(app);

Now let’s use the wrapped server to set up a WebSocket to listen to GraphQL subscriptions.
server.listen(PORT, () => { new SubscriptionServer( { execute, subscribe, schema: Schema, }, { server: server, path: '/subscriptions', }, );
console.log(`GraphQL Server is now running on ${BASE_URI}`); console.log(`Subscriptions are running on ${WS_BASE_URI}/subscriptions`); });

The last thing in this step is to configure GraphQL Playground to use the subscriptions WebSocket we just set up. We use it as a server middleware and the graphql-playground-middleware-express package is all we need. If you use another server framework (such as Hapi or Koa), you’ll find the proper packages here as well.

Import desired package:
import expressPlayground from 'graphql-playground-middleware-express';

And adjust the endpoints:
app.get( '/playground', expressPlayground({ endpoint: '/graphql', subscriptionsEndpoint: `${WS_BASE_URI}/subscriptions`, }), );
. . .

Declaring subscriptions in the schema and adding a subscription Resolver

Now let’s define subscriptions in our GraphQL schema.
// RootSubscriptions.js
import { GraphQLObjectType } from 'graphql';
import NewCat from './NewCat'; import RemovedCat from './RemovedCat';
export default new GraphQLObjectType({ name: 'RootSubscription', description: 'Root Subscription', fields: { newCat: NewCat, removedCat: RemovedCat, }, });

Right after that we’ll construct an instance of PubSub to handle the subscription topics for our application.
// serverConfig.js
import { PubSub } from 'graphql-subscriptions';
export const pubsub = new PubSub();

Creating a subscription resolver is very similar to queries and mutations. The only difference is that instead of passing only the resolve function, we also pass object with the subscribe method, which should return the asyncIterator function of the PubSub.
// newCat.js
import { pubsub } from '../serverConfig'; import GraphQLCat from '../outputs/Cat';
import type { Cat } from '../types/Cat';
export default { type: GraphQLCat, subscribe: () => pubsub.asyncIterator('newCat'), resolve: (payload: Cat) => payload, };

As soon as our subscription resolver is ready, we can start publishing new Cat into it. For that we just call thePubSub method pubsub.publish('newCat', cat) inside theaddCat mutation.
// addCat.js
export default { ... resolve: async ( _: mixed, args: argsType, { Cat }: GraphqlContextType, ): Promise<CatType> => { const payload = { ...args, createdAt: new Date().toISOString(), }; const cat = await new Cat(payload).save(); pubsub.publish('newCat', cat); return cat; }, };

Let’s get back to the browser and finally try it out by running the following query:
subscription newCat { newCat { id name nickName description createdAt avatarUrl age } }

Playground is now listening for the creation of a new Cat and as soon as theaddCat mutation is triggered, you should see it in your Playground window!
mutation addCat { addCat(name: "Pussie Cat", nickName: "pussie", description: "Ooops, I killed a mouse", avatarUrl: "", age: 5) { id name nickName description createdAt avatarUrl age } }

. . .

Demo time

Congratulations! You have implemented your first server-side GraphQL Subscriptions through WebSockets! You can find the complete source of this example on my GitHub.

Never miss a post from Snehal Kumar, when you sign up for Ednsquare.