Real-time Chat Application With AWS Websockets

Suminda Niroshan
The Startup
Published in
5 min readSep 27, 2019

Sometimes web applications requires the server to notify about something as soon as possible to the client. Without Websockets the client would need to have some kind of polling mechanism and keep checking with server for new data. This is not ideal and would result in sending unnecessary requests.

A Websocket advantages are,

  • Bidirectional or Duplex communication between the client and the server which eliminates the need for the client to poll for new data.
  • Since data will be sent after a connection is established, there’s low latency in requests and responses as there’s no need for sending additional packets for connection establishment.

AWS supports Websockets in API Gateway. This is what we’ll be using for the simple chat application we’re building.

To keep things really simple and to give more focus to Websockets, the sample web application will only be consist of HTML and Javascript, no other fancy libraries used and the AWS Websockets server will be handled by Lambda functions with a Python runtime.

Prerequisites

You need to have an AWS account and some basic knowledge working with AWS services and how to deploy with Serverless Framework. Following AWS services will be utilised throughout this guide.

Make sure to have the following installed,

We’ll be using Serverless Framework to configure and deploy the whole infrastructure needed. So we don’t need to go to AWS console and create resources manually. Please refer to this blog post if you need help on setting it up.

You will learn

How to leverage AWS Websockets for duplex communications in web applications.

AWS Websockets

AWS Websockets API consists of one or more routes. Routes are used to redirect incoming requests to a particular HTTP endpoint or a Lambda function to handle it.

There are 3 main routes,

  • $default — This route is used when a request comes without specifying which route to take.
  • $connect — This route is used whenever a client connects to the Websocket API.
  • $disconnect — This route is used whenever a client disconnects from the Websockets API.
  • Custom — These routes are defined by us to handle custom routes.

Application Architecture

Figure 01 — Application Architecture

In order for server to handle websocket communication between clients, it needs to persist connected client information somewhere. A DynamoDB is used here for this purpose.

There are 3 main routes being used (Refer to Figure 01). Disconnect, connect and a custom route.

Following sequence will take place when clients communicate with AWS Websockets API.

[1]. Clients makes requests to the AWS Websocket API to connect.
[2]. AWS API Gateway invokes the Lambda function that is responsible for handling client connect events.
[3]. The lambda function saves the client ID in a DynamoDB table to persist connected client IDs.
[4]. Client makes a request to the AWS Websocket via the custom route to distribute a message to other connected clients.
[5]. The lambda function retrieves all connected client IDs and broadcasts the received messaged to all connected clients.
[6]. A lambda function will be invoked whenever a certain client disconnects from the AWS Websocket. This function will remove the client ID from the DynamoDB table.

Connect Route Handler code

connect_handler.py

Please refer to the code above which handles adding connected client IDs to the DynamoDB table. This represents the step [3] in the sequence.

Custom Route Handler code

This code is responsible to query the database and send the received messaged for all client IDs in the database. This represents the step [5] in the sequence.

Disconnect Route Handler code

This code is responsible to delete client IDs from the table whenever a client is disconnected from the AWS Websocket. This represents the step [6] in the sequence.

For all 3 handlers, the DynamoDB table name will be passed as an environment variable called “ SOCKET_CONNECTIONS_TABLE_NAME”. This will be configured in “serverless.yml” file.

The DynamodDB is accessed via Boto3 Python library. This is added to all the Lambda functions as a Lambda layer in the “serverless.yml” file.

Following is the serverless.yml file for the AWS infrastructure. Again if you don’t know how Serverless Framework works, please have a look at this blog post.

Let’s break down the function components in the serverless.yml.

Apart from AWS environment settings which I have explained in my other blog post, you can see the 3 route handlers defined in the serverless.yml as connectHandler, disconnectHandler and onMessageHandler and their respective code files.

When a client establishes a connection, connectHandler lambda function will be invoked.

When a client disconnects, disconnectHandler lambda function will be invoked.

Please note the following snippet in onMessageHandler configuration.

route: onMessage

This means that the client should send the message to AWS Websocket with the action as “onMessage”. This would result in the invocation of onMessageHandler lambda.

{“action”: “onMessage”, “message”: “Hi from websocket!”}

Deployment

1. Get the source code from this Github Repo and go in to the project directory from your CLI.

2. Install required npm packages first.
$ npm install

3. Install Serverless Framework globally.
$ npm install -g serverless@1.48.2

4. Install required Python packages
$ pip install -r python-packages.txt -t ./lib/python

5. Deploy into AWS
$ serverless deploy --stage websocket

After the deployment, you should get the AWS Websocket endpoint as displayed below.

Now open the “index.html” file and replace WEBSOCKET_ENDPOINT_URL with the endpoint URL as displayed. This sample client chat app is made of purely HTML and JavaScript. No libraries used.

Testing

Open the “index.html” file in multiple browser windows (I have opened 3) and click “Connect” on all clients. After the connection is open, type a message in the input field and click “send”. This will broadcast the message to all clients connected. Check it out in action below.

--

--