DEV Community

loading...

Detailed Guide on How to use Websockets with AWS Serverless?

shivangchauhan7 profile image Shivang Chauhan Updated on ・8 min read

Introduction

In this blog post, I am going to show you how to use Websockets with AWS serverless, this post will have the steps you need to take to integrate web sockets with AWS serverless using Node Js, at the end of this blog post you will have an application where you can create a chat room and other users can join your room to chat with each other in a custom room, I made the procedure very simple to follow, at the end of this post you will also get a link to Github repository for the code.

Project Setup

The first thing is project setup and installing the required project dependencies, for this create an empty folder with the name of your choice, after the project folder is created cd into the project and run –

npm init
npm i aws-sdk --save`
Enter fullscreen mode Exit fullscreen mode

Create a folder named src at the root of the project and inside src folder, you need to create four more folders with index.js files in each folder –

connectionHandler:- This folder will contain the file to handle the connect and disconnect events of WebSockets.
manageRoom:- This folder will contain the file to create/join the chat room.
sendMessage:- This folder will contain the file to emit the message to all connected users in a particular room if any user in the room sends a message.

By now your project structure should look like this –

Alt Text

Now you have the basic project setup and you are ready to move to the next step which is creating the serverless.yml file, we will go through what this file does in brief in the further parts of this guide.

Creation of serverless.yml file

This is the first step to learn how to use Websockets with AWS serverless technologies, so let’s get started.

What is a serverless.yml file?

In a very simple language, serverless.yml file is used to code out the template according to the resources you want to create in your AWS account, you can define different types of resources in serverless.yml file and you can also set the different permissions for different resources.

In this project, the main use of serverless.yml will be to create the Lambda functions and to set up the Dynamo DB Table with permissions.

Defining configuration and permissions block in serverless.yml file

Alt Text

This is the first part of your serverless.yml file, let’s break it down in parts for you –

service:- This is just the name of the CloudFormation template which will be created in the AWS account.
provider:- You define configuration, environment variables, different permissions, roles in this block, here in this code you are defining things like version of Node Js you want to use in your AWS environment.
websocketsApiRouteSelectionExpression:- This is the custom route selection expression, meaning if you want to emit custom events from your WebSocket client then you will be passing the event name as the value of a property named action in the body payload of the request.
Action:- This block has all the actions which we want to perform on our Dynamo DB Table using our lambda functions.

Defining functions block in serverless.yml file

Alt Text

This is where you will define all your Lambda functions to be created, let’s break it down a little bit for better understanding –

connectionHandler function:- This is the Lambda function which will be called when any user connects to or disconnects from your WebSocket server, there are three predefined events or routes defined by API Gateway$connect, $disconnect and $default.
$connect/$disconnect:- When the user connects to your WebSocket server $connect is the default event that gets called and when the user disconnects $disconnect event gets called.
sendMessage:- This function will be called if the user sends sendmessage as the value of action property in the request payload, it handles sending messages to all connected users in a particular room.
manageRoom:- This function is used for creating/joining a room according to room id.

Defining resources block in serverless.yml file

Alt Text

This is your resources block in serverless.yml file, you define all the resources you want to automatically create in AWS account, we are only creating a new Dynamo DB Table with a Hash key or in another language Primary key if you come from SQL background.

Connecting and disconnecting users

Let’s start working on the Lambda function to connect or disconnect WebSocket clients, you are using connectionHandler function to handle this functionality, it will look something like this –

Alt Text

Don’t worry we will go through each part of the function in detail, so let’s start with the first part? which is handling the connected users.

Connecting users

Alt Text

What you are doing here is checking if the user got connected using API Gateway WebSocket URL and if the user got connected you are getting the connectionId from the event.requestContextobject and creating a new entry in Dynamo DB Table with connectionId value, so this is just a simple insert operation on Dynamo DB Table with connectionId.

What is .promise() ?

If you are wondering why we are using .promise() here then it is used because you want to write clean and short code as best of your ability so you want to use async/await instead of callbacks, but to use async/await the function call must return a Javascript promise that is why we are using .promise() call, most of the functions in AWS-SDK has an option to use promise() which allows the function to return the result in a promise instead in a callback.

Disconnecting users

Alt Text

You are checking here if the user got disconnected from WebSocket server and if the user got disconnected then connectionId is used to remove that user entry from Dynamo DB Table.

Creating and joining chat rooms

The next thing is to set up a Lambda function to allow users to create or join a room, the code of the function will look something like this –

Alt Text

Let’s break the code in different parts for a better understanding
of the code.

Getting and checking the room id

Alt Text

Here you are getting the request body and parsing it as JSON data and you are also checking if roomid is not present in the body object or not because roomid is required if the user is trying to create/join a chat room.

Creating/join the chat room

Alt Text

Here you are updating an entry in Dynamo DB Table according to the connectionId and also setting the column roomid with the value which is passed by the user in the request body, so for example if connectionId is #f!41fg and roomid passed by user is test-chat-room then what this code will do is update the roomid column with the value test-chat-room in the row where connectionId is #f!41fg.

Sending a message to all connected users in the chat room

Now the final part of our project is to create a Lambda function to send a message to all connected users in a chat room if any user in the room sends a message, code for this function will look like this –

Part – 1

Alt Text

Part – 2

Alt Text

Let’s break down this function in different parts for better understanding.

Getting all connection id’s according to room id

Alt Text

When any user sends any message in a chat room, they must send the roomid, then you will use that roomid to find all the users connectionId’s associated with that roomid, here in this above you are using the roomid to find the records from Dynamo DB Table and storing all that data in a variable called connectionData.

Sending a message to all connected users in a chat room

Alt Text

Here is the code which handles the functionality of sending a message to other users which are connected in a chat room if any member in chat room sends any message, Let’s go through this code in details –

Use of ApiGatewayManagementApi

Alt Text

ApiGatewayManagementApi is used to send the data to an endpoint, what you are doing here is create an instance of this class to use the methods which ApiGatewayManagementApi provides, you are also getting the endpoint on which you are going to send the data from event data of your Lambda function.

Send the message in a chat room

Alt Text

If you are not familiar with javascript this code might seem confusing, what you are doing in this code is mapping through all the data which connectionData has if you remember connectionData is the collection of connectionId’s of users which are in a chat room.

  • postToConnection is the method which you are going to use to send a message to all the connected users in a chat room using the connectionId of the user.
  • Data property is the data that you want to send to the connected sockets.
  • postCalls will have the collection of pending Javascript Promises which are posting a message to each user in a particular chat room using user’s connectionId.

Using postCalls to resolve all the promises

Alt Text

You are passing postCalls which is a collection of pending promises into a function called Promise.all(), so what this function requires is an iterable array of promises and it returns a single promise resolved with an array of data after resolving each promise in an array, in easier words Promise.all() is going to send message to all the users in a chat room.

Woo! you are now Done! writing the code, it’s time to test this stuff out

You need to run sls deploy to deploy your code to the AWS and then you will get a URL which will look something like this –

URL – wss://{YOUR-API-ID}.execute-api.{YOUR-REGION}.amazonaws.com/dev

These are the steps you need to take to test this chat application –

  • Install an NPM named wscat by running this command – npm install wscat -g
  • Now run this command inside the terminal – wscat -c {your API Gateway URL} (without {}).
  • If you see this output –

Alt Text

then you are now connected to your Websocket server.

  • Now let’s create a new room named test room by sending this data – {“action”:”manageroom”,”roomid”:”test room”}.
  • After sending this data, you can go to your Dynamo DB Table and check if a new entry is created there or not with a connectionId with roomid.
  • This connection will work as one user who created a room and now is inside the chat room, let’s repeat this same process for another user by opening a new terminal window and running the same process from Step 2.
  • Now after repeating this process from another terminal window, check the Dynamo DB Table, if it has another entry with the same test room value as roomid then congrats your manage room code is working perfectly.
  • It’s time to send your first message by sending this data – {“action”:”sendmessage”,”roomid”:”test room”,”message”:”Hi there!”}.
  • If you see this output on both terminals -

Alt Text

then congratulations you have successfully posted your first message, now when any of the connected users send any message it will be shown to all the users which are in that chat room.

How to get this code?
https://github.com/shivangchauhan7/serverless-chat

Discussion (2)

Collapse
farhajhussain44 profile image
Collapse
shivangchauhan7 profile image
Forem Open with the Forem app