Real-time Chat Application With AWS Websockets
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.
- Lambda Service
- AWS API Gateway
- AWS Websockets
- AWS DynamoDB
Make sure to have the following installed,
- Node 6.0 or later
- Python 3.7 or later
- Pip3
- AWS CLI Configured for your account
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
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
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.
Summary
You can see how easy and seamless AWS makes when it comes to dealing with Websockets. You can utilize these in every application that requires live data transfer between other applications.