Subscriptions with GraphQL

First of, I found this a time consuming task just to figure out where to start, how to test this functionality and whehter I should switch to use Apollo instead, as there are many resource out there that show how subscriptions work well with their approach, not to forget the Apollo graphiql tool allows you to test subscriptions.

After a lot of searching, many articles read and videos watched, I kept coming back to GitHub’s graphql/express-graphql issues page where several people, dating back to August 2017 have been wanting to implement subscriptions.
As my project is build using express and express-graphqlI wanted to make it work and not give in to Apollo 😁

My project uses graphql-ws from enisdenjo/graphql-ws — an amazing repo and contains everything you need to get it working for front and back end solutions.
I also recommend reading Denis Badurina’s blog post on GraphQL over WebSockets, it’s a great read.

Throughout this article, I’ll share some snippet’s of my project for each part affected by subscriptions.

Let’s start with the server setup.

GraphQL Server

Make sure you have graphql-ws , ws and graphql-subscriptionsadded to you package.json file.

npm install graphql-ws ws graphql-subscriptions

In the snippet below, we have our standard express-graphqlserver with the WebSockets server running of express.

index.js

TypeDefs

Our schema file user.types.js contains our User schema definition. I’ve added a subscription operation of newUser , this will let us know when a new user has been created using the createUser mutation.

type Query {        
login(input: UserLogin!): String
users: [User]
user(id: ID!): User
}
type Mutation {
createUser(input: UserMutation): User
updateUser(input: UserMutation): User
deleteUser: String
}
type Subscription {
newUser: User!
}
type User {
...

Resolver

Next, the user.resolver.js this is where we hook up the event to the subscription using PubSub (Publish/Subscribe pattern).

I’ve created a helper module to import the PubSub instance.

const { PubSub } = require('graphql-subscriptions')
const pubsub = new PubSub()
module.exports = pubsub

PubSub

PubSub is a class that exposes a simple publish and subscribe API.

It sits between your application’s logic and the GraphQL subscriptions engine — it receives a publish command from your app logic and pushes it to your GraphQL execution engine. Apollo documentation

NOTE that the default PubSub implementation is intended for demo purposes. It only works if you have a single instance of your server and doesn’t scale beyond a couple of connections. For production usage you’ll want to use one of the PubSub implementations backed by an external store. (e.g. Redis)
[from graphql-subscriptions — npm]

Continuing…

The pubsub.publish function happens inside the createUser function and has 2 arguments,
1.triggerName — A string identifier
2.payload — An object with the subscription type newUser , as defined in the user.types.js schema definition, along with the data to return.

The Subscription property on the resolver is similarly written like Queries and Mutations but notice it has a subscribe method that returns AsyncIterable , with the same triggerName value as the publish function.

user.resolver.js

How does it work?

The client listens (subscibes) to the newUser and waits for the NEW_USER_EVENT to be triggered.

As soon as createUser is called, it says, if anyone listening with NEW_USER_EVENT , I’m going to send (publish) this newUserobject with the data.

Now that the server has been setup, it’s time to setup the client.

Client:- Angular & RxJS

As mentioned earlier, the graphql-ws GitHub page has many examples of how to implement its package for server or client. As I’m a big Angular fan and one of the example used, was using Observables, I will be Angular and RxJS to connect to our subscription.

If you are not familiar with Angular or RxJS please check the recipes for graphql-ws, if you are, great, let’s go.

These are the additional packages required for the Angular project.

npm i graphql graphql-ws graphql-request

graphql-request is a GraphQL client supporting Node and browsers for scripts or simple apps and also recommended on graphql.org.

Even though it’s not used with subscripions, it’s perfect for queries and mutations, and I’ll leave it in the snippets for reference.

To keep it tidy and stuff it all into one file, we’ll create a service for the GraphQL server calls, this way we keep the app DRY and another service for our queries.

GraphQL Service

You can see there is a fetch method for queries and mutations, this returns an observable but by default returns a Promise.

The subscription method for… subscriptions. NgZone is used inside our subscription to update client windows.

graphql.service.ts

User Service

Next, is the user service, here we write our queries to be consumed by our components.
createUser is the mutation query which returns the firstName and email and the newUserEvent is the subscription which returns the id of the created user.

user.service.ts

App Component

In our app.component.ts file we’ve created an observable called createUserEvent$ which will return the newUser data and log it in the console.
The createUser function sends the mutation, triggers the subscription and returns the createUser data to the console.

app.component.ts

You can now call createUser() in the view (app.component.html ) to create the user. Make sure you’ve subscribed to the createUserEvent$ using the async pipe.

<button (click)="createUser()">create user</button>{{(createUserEvent$ | async) | json}}

Nice, open another browser and see it work in real-time.

That’s all you need to do to get it working.

I have both example projects on GitHub and each has more than just these subscription snippet examples.

shammelburg/express-graphql-api — GraphQL server

shammelburg/graphql-rxjs-angular — Angular application

My Experience

I’ve had a lot of fun putting these projects together and testing the functionality for both. I really like how subscriptions work and I can think of many scenarios where it would be useful.
I’m going to use GraphQL in my next project with Angular off course 😁 and it’s going to be a blast.
The great thing about using express is that you can still use REST endpoint for file uploads, etc.

There is still much to learn.

I hope you enjoyed this, thank you for reading.

Happy coding!

Lead Developer. Angular. Node. GraphQL. JavaScript enthusiast.