Building a realtime chat app with GraphQL Subscriptions
Tags: graphql, realtime, postgres, chat
Published: 2019-12-16 13:21:50

---
title: Building a realtime chat app with GraphQL Subscriptions
published: true
date: 2018-09-06 00:00:00 UTC
tags: graphql, realtime, postgres, chat
canonical_url: https://blog.hasura.io/building-a-realtime-chat-app-with-graphql-subscriptions-d68cd33e73f/
---

### Here is how I used subscriptions in Hasura GraphQL Engine to build a [full-fledged real-time group chat app](https://realtime-chat.demo.hasura.app/) on Postgres with React and Apollo.

![](https://blog.hasura.io/content/images/2019/12/GraphQL---Apollo.png)

## TL;DR

- Hasura GraphQL Engine provides real-time GraphQL APIs to query PostgreSQL tables.
- Not a single line of backend code is written.
- Subscriptions are used for event notifications and not for fetching data. Whenever an event occurs, a GraphQL query is used to fetch only the new messages. This way we do not re-fetch the same data.
- A `user_online` event with the current time-stamp is emitted every two seconds in the form of a mutation. A subscription is used for getting a list of online users that updates realtime.
- A `user_typing` event with the current time-stamp is emitted every time a user types a few characters (in the form of a mutation). A subscription fetches the user that typed last.
- Links: [App](https://realtime-chat.demo.hasura.app/), [GraphQL Engine Console](https://hasura-realtime-group-chat.herokuapp.com/console) and [Github](https://github.com/hasura/graphql-engine/tree/master/community/examples/realtime-chat).

## Introduction

You can build a fully functional realtime chat application without writing a single line of backend code. [Hasura GraphQL Engine](https://hasura.io) provides instant realtime APIs over Postgres. This means that you can simply create tables and start querying the data in the tables over HTTP (queries and mutations) and Websocket (subscriptions).

This blog talks about building a real-time group chat using GraphQL subscriptions. It is more of a philosophical rant about modelling your data and consuming the data from the front-end. Code subtleties are not covered; if you are interested in seeing the code [check out this git repo](https://github.com/wawhal/graphql-subscriptions-chat-app).

**Prerequisites** :

- Knowledge of consuming a GraphQL API i.e. Queries, Mutations and Subscriptions.
- Fundamentals of React.

Although we will talk in the context of a group chat app, you can use these ideas for making any kind of realtime chat application.

## Data Modelling

### **Users**

To store the users, we will make a user table.

{% gist https://gist.github.com/wawhal/ad677d810cd092c847bf1d955ea7a3f7.js %}

We are not adding auth in this application, but you can if you wish to. You have to insert the user in this `user` table whenever a user signs up. If you are adding auth, it can have more fields like `email` , `mobile_number` , `location` etc.

The fields `last_typed` and `last_seen` are to track the user’s activity for functions typing indicators and online users.

### Messages

We will store messages in the `message` table.

{% gist https://gist.github.com/wawhal/4c7b621cf9626c7f694f89992fa6a6eb.js %}

In this case, this table is being used for a single group chat, so it does not have fields like `chat_id` , `is_deleted` etc. You can add all these fields for more complex examples

We will be selecting(querying) data and inserting data into this table. This application does not support updating or deleting the messages. You can implement that super easily using `update_message` and `delete_message` mutations. The root fields generated by the GraphQL Engine for this table are:

### Online users

This chat app also lists down the number of online users. To do this, we will create a view over the `users` table.

{% gist https://gist.github.com/wawhal/457c328b17544deb610881d386713899.js %}

This view contains the list of users that had updated their `last_seen` less than 10 seconds ago. This view gives us information about online users.

### Typing indicator

To show whenever someone is typing, we have a `last_typed` field in the `user` table. We will create a view over the `user` table called `last_typed_user`.

{% gist https://gist.github.com/wawhal/8fba8f69721efb7f59a820cc26cdd2f5.js %}

This view contains the users that have emitted a `typing` event less than two seconds ago.

## Implementing the front-end

### Setting username

Since we don’t have auth implemented in this app, we will prompt for username whenever the app loads. This username is stored by inserting it in the `user` table as a mutation.

{% gist https://gist.github.com/wawhal/5c07a8cd94aceaefe9412b7ed7f4a4a1.js %}

Once the mutation is completed, we render the chat screen with the props `user_id` and `username`.

### Emitting online events

We are going to render a list of online users in this app. To get the list of online users, we need all users to emit `online` events every 2 seconds. This is done in the `componentWillMount()` of the root component after entering the username. The users will emit this “online event” in the form of an `update` mutation to the `user` table where we update the `last_seen` column with the current timestamp .

{% gist https://gist.github.com/wawhal/3f75d740af5e399d4d199dc86c168d9c.js %}

### Subscribing to messages

GraphQL Subscription can be used in two ways:

1. We can subscribe to a query and render the data that we receive.
2. We can treat a subscription as an event notification and run custom logic every time we receive an event.

We will use the second approach. This is because, if there are a lot of messages in the group chat, we do not want to keep receiving them again when we already have them. The algorithm to fetch messages is as follows:

1. On first load, we fetch all the messages that exist in the `message` table. The query we use is:

{% gist https://gist.github.com/wawhal/0369d0eb81dcbc2b1851fa19de3bb811.js %}

On first load, we set `$last_received_id` to `-1` and `timestamp` to an ancient timestamp so that all messages are loaded. We also order the messages in ascending order of `timestamp` so that we get the messages in the correct order.

2. Now we subscribe to the last message added in the `message` table via the subscription:

{% gist https://gist.github.com/wawhal/99d019e69fab0e252a0940b766b4ad8c.js %}

3. Now, whenever we get the data from the above subscription, we can refetch the messages using the previous query but with new variables. The `$last_received_id` will be the id of the latest message in our client state and the `$last_received_ts` will also be the timestamp of the latest message in our client state.

In this way, we fetch chat messages in realtime and we also avoid fetching the same data multiple times.

### Sending messages

Since we have the `username` of the user in the state, we can insert messages in the database with a mutation:

{% gist https://gist.github.com/wawhal/73527ee1ddadf65b872bc1d5bee780bd.js %}
### Typing Indicator

When the user is typing a message, we emit one `typing` event for every few characters that the user types. This typing event is emitted in the form of an update mutation to the `user` table by updating the field `last_seen` to the current timestamp.

{% gist https://gist.github.com/wawhal/2cf2a8ff39415c3713ab20483d8a8987.js %}

Now that every user is emitting a `typing` event every time they type a few characters, we can run a subscription to the last user that typed in the past 2 seconds. Remember, we created a view for this functionality. Also, we don’t want to see ourselves typing, so we filter ourselves out while making the subscription.

{% gist https://gist.github.com/wawhal/3856009cca8e650cd8dcd10f55fbede8.js %}
### Online users list

As we mentioned before, every user emits an `online` event every 2 seconds. Using these events, we can render a list of online users that updates realtime. We simply have to subscribe to view `user_typing` and its done.

The subscription is:

{% gist https://gist.github.com/wawhal/d72c725bf08082a8aee4db79db73348c.js %}