Real Time GraphQL — Chat (Part 1 Server)

I always ask people…

Do you really need real-time?

This question really boils down to your data-access patterns in product. If most of your specifications are static lists or content, then having a simple request and response transport coupled with a caching client can serve most of your needs.

This is what is I love about GraphQL technologies, they are optimized for the majority use case and give you alternative methods to keeping data fresh:

Previous Real Time Experience

Coming from the Meteor community previously, data access was “real-time” via a piece of technology called DDP (Distributed Data Protocol). This allowed the engineer to create a subscription on the client for pieces of data, sent over WebSockets via “live-queries”.

This real-time solution works great for experiences demanding real-time feature sets, and having your data refresh on screen in response to any document changes is magical, but it leads to tons of waste. In this pub sub system you would, using Mongo Syntax, enforce the data over the wire via “projections”. A client developer would specify fields they need to render UIs and the system will react to any changes to the data in those underlying fields.

This is where it gets suboptimal. In many user interfaces there are a collection of data points used to present information that is static. So if most of your data is static, you incur a higher cost than its worth with live-queries.

Ideally, we only want to update the piece of state we as product developers deem necessary to keep the data and UX consistent. This is where event based subscriptions come in.

GraphQL Subscriptions

The most popular way to do subscriptions in GraphQL today is via an Event Based Subscription. Let’s look at how this happens.

The current state of the art around GraphQL Subscriptions center around a topic-based publish/subscribe model. “Messages” are published to “topics” or “channels”. Subscribers in these systems receive all messages to which they subscribe and all subscribers receive the same messages. The publisher, our server, is responsible for defining these topics and the types of messages that are published to them.

The idea here is to create topics around state mutations, and publish messages along with metadata to subscribers. Our main subscriber, the client, will get a message and “react” to the message with some work.

Credits to Johannes Schickling

We can enhance simple request/response GraphQL queries by subscribing to topics that mutate the underlying data backed by the query and merge changes to into the UI.

Example

The full server repo can be found here.

Today I’d like to walk through a really simple use case for a GraphQL Subscription. The most “real-time” feature I could think of would be Messaging. So let’s build a little Chat Service and in the next chapter we’ll build the UI!

Type Definitions

To get started let’s add a Subscription Type to our GraphQL type definitions.

We have defined a Subscription named messageAdded which we will execute whenever a message has been added to the chatroom.

Resolvers

Next given this base set of resolvers, we are going to add a subscription resolver:

PubSub

Subscriptions are another ROOT_TYPE in GraphQL. To get situated with subscriptions we need to install the graphql-subscriptions module.

yarn add graphql-subscriptions -S

Next we’re going to create our Publisher. graphql-subscriptions comes with a nice event emitter to get yourself acquainted with subscriptions, but it is advised you back this via a more production grade solution. My personal favorite is:

For now we’ll go with the PubSub class shipped with graphql-subscriptions

It is important to note that unlike Queries and Mutations, Subscriptions resolvers are not functions. They are maps with a subscribe method and return an AsyncIterable. We use pubsub’s asyncIterator to map over the topics available and pick the messageAdded channel. We then use withFilter to make sure that this channel only publishes data in the current chatroom. We do this by looking at the chatroomId incoming from metadata and the chatroomId supplied by the subscription. Filters leave room for tons of customizability for subscriptions, I encourage you to play with it!

Great! Our GraphQL server is well aware that messageAdded is a subscription. We now need to add the hooks in triggering the publish of a specific topic.

Publish

We’ll use the pubsub’s publish method to publish metadata to a specific topic. In this case, messageAdded.

When a message is created via our addMessage mutation, we publish to the messageAdded channel the metadata of the message just created.

SubscriptionServer

The last thing we need to do is expose a WebSocket that clients can connect to. This will allow us to push data to these clients in response to our event based subscriptions.

Here we take our express server and bind it to a httpServer from node. We then create our SubscriptionServer.

We bind our

With that in place we are ready to connect our client!

Conclusion

Tune into the next post to see how the UI fits into our newly added Subscriptions! With the Subscriptions RFC merged into GraphQL, we are going to see a lot of movement in this space for the coming future. I’d keep a close eye on developments, and pay special attention to Urigo as he is really championing this space for the Angular community!

Cheers!

Software Engineer at Workpop, Inc.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store