Build Serverless Chat App with a WebSocket API and Lambda

In this article, we are going to develop Hands-on Lab: Build Serverless Chat App with Amazon API Gateway WebSocket API and AWS Lambda.

Hands-on Lab: Build Serverless Chat App with Amazon API Gateway WebSocket API and AWS Lambda

In this hands-on lab, we basically create a Serverless WebsocketAPI that provides bidirectional communication for chat application and store message items into DynamoDB table.

I have just published a new course — AWS Lambda & Serverless — Developer Guide with Hands-on Labs.

API Gateway WebSocket API

A collection of WebSocket routes and route keys that are integrated with backend HTTP endpoints, Lambda functions, or other AWS services. We can Build real-time two-way communication applications, such as chat apps and streaming dashboards, with WebSocket APIs.

In a WebSocket API, the client and the server can both send messages to each other at any time. Backend servers can easily push data to connected users and devices, avoiding the need to implement complex polling mechanisms. We can use API Gateway WebSocket APIs to build secure, real-time communication applications without having to provision or manage any servers to manage connections or large-scale data exchanges.

We can say, the main core concepts of WebSocket APIs are;
— Routes
— Integrations
— Stages

We have 2 Route type
— Predefined routes
— Custom routes

In Predefined routes, We have $connect, $disconnect and $default routes. The $connect route is triggered when a client connects to your API.
The $disconnect route is triggered when either the server closes the connection. The $default route is triggered if the route selection expression if no matching route is found.

Hands-on Lab: Build Serverless Chat App with a WebSocket API and Lambda

In this hands-on lab, we basically create a serverless Chat app that we connect, sendMessage and disconnect with websocket api. We will handle incoming bidirectional request from Websocket API of API Gateway into Lambda function and return back to immediate response.

Hands-on Lab: Build Serverless Chat App with Amazon API Gateway WebSocket API and AWS Lambda

When you create connection and send message to Websocket API, API Gateway routes the request to your Lambda function. The Lambda function can be interacts with database, and returns a response to WebSocket API.

Create Lambda function

We create a Lambda function for the backend of your API. This Lambda function handles all websocket calls like connect, sendMessage, disconnect and so on. The function uses events from API Gateway to determine how to perform chat operations.

Goto Console — Lambda — Choose Create function. — For Function name, enter — chat-function — Choose Create function.

Let me add logging — console.log(“event:”, JSON.stringify(event, undefined, 2));

LAMBDA CODE:
exports.handler = async (event) => {
console.log(“event:”, JSON.stringify(event, undefined, 2));
// TODO handle events coming from api gateway http api and perform crudconst response = {
statusCode: 200,
body: JSON.stringify(‘Hello from Lambda!’),
};
return response;
};

Create WebSocket API

We’ll create a WebSocket API to handle client connections and route requests to the mock functions. In your WebSocket API, incoming JSON messages are directed to backend integrations based on routes that we configure.

Choose Create API — Then for WebSocket API, choose Build. For API name, enter — websocket-chat

For Route selection expression,— enter request.body.action.

We will send a json object like:

{
“action”: “sendMessage”,
“message”: “Hello from websocket chat app !”
}

So we put in default value here — request.body.action. So in which action comes in this parameter, we will forward that message to the corresponding route.

For Predefined routes, choose Add $connect, Add $disconnect, and Add $default. For Custom routes, choose Add custom route. For Route key, enter — sendMessage.

Under Attach integrations, for each route and Integration type, choose Lambda.

Choose Create and deploy.

Understanding How WebSocket API Trigger Lambda with Event Json Object

We are going to Understand How WebSocket API Trigger Lambda with Event Json Object and after that we will develop our lambda function with incoming event to perform crud operations.

Choose Stages, and then choose production. See deployed urls:

Note your API’s WebSocket URL. The URL should look like wss://abcdef123.execute-api.us-east-2.amazonaws.com/production.

Go first result:
- https://www.piesocket.com/websocket-tester

Now we will test our websocket in here. First step is establish connection, Copy your WebSocket Url which starts with wss and paste here — Click Connect, See Logs
- Connecting to: wss://xx.execute-api.us-east-2.amazonaws.com/production
- Connection established

Lets check incoming event to lambda function:

CONNECT :2022–05–25T08:06:45.998Z a9a72e18-ef5b-4e06–8d20–25edf14016be INFO event: {
“headers”: {
“Accept-Encoding”: “gzip, deflate, br”,
“Accept-Language”: “en-US,en;q=0.9,tr-TR;q=0.8,tr;q=0.7,de;q=0.6,es;q=0.5,ru;q=0.4,th;q=0.3”,
},
“requestContext”: {
“routeKey”: “$connect”,
“eventType”: “CONNECT”,
“extendedRequestId”: “SrB_bGFdCYcF-zA=”,
“requestTime”: “25/May/2022:08:06:45 +0000”,
“messageDirection”: “IN”,
“stage”: “production”,
“connectedAt”: xxxxx,
“requestTimeEpoch”: 1653466005751,
“identity”: {
“userAgent”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36”,
“sourceIp”: “24.133.212.235”
},
“requestId”: “SrB_bGFdCYcF-zA=”,
“domainName”: “xxxx.execute-api.us-east-2.amazonaws.com”,
“connectionId”: “xxxx=”,
“apiId”: “xxx”
},
“isBase64Encoded”: false
}

So this is the event json object that trigger to lambda function from HTTP API gateway.

If you check this, we can find important parameters like;
“requestContext”: {
“routeKey”: “$connect”,
“eventType”: “CONNECT”,

According to this parameters we can identify incomming route and http method. Let me send a sendMessage request to web socket api, after we have connected the our chat application, we can sendMessage:

{
“action”: “sendMessage”,
“message”: “Hello from websocket chat app !”
}

See Logs:

2022–05–25T08:07:09.985Z 704b5cfa-a95f-4040–9cd6–070e4ab06c16 INFO event: {
“requestContext”: {
“routeKey”: “sendMessage”,
“messageId”: “SrCDNdVACYcCIRQ=”,
“eventType”: “MESSAGE”,
“extendedRequestId”: “SrCDNGr5iYcF4xw=”,
“requestTime”: “25/May/2022:08:07:09 +0000”,
“messageDirection”: “IN”,
“stage”: “production”,
“connectedAt”: xxxx,
“requestTimeEpoch”: 1653466029973,
“identity”: {
“userAgent”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36”,
“sourceIp”: “24.133.212.235”
},
“requestId”: “SrCDNGr5iYcF4xw=”,
“domainName”: “xxx.execute-api.us-east-2.amazonaws.com”,
“connectionId”: “xxxxx=”,
“apiId”: “xxxx”
},
“body”: “{ \”action\”: \”sendMessage\”, \t\”message\”: \”Hello from websocket !\” }”,
“isBase64Encoded”: false
}

According to this parameters we can identify incoming route. You can see the body information.

Develop Lambda Function for Incoming WebSocket API Event Json Object

we are going to Develop Lambda Function for Incoming WebSocket API Event Json Object to perform crud operations. Lets get started. Develop our logic:

const AWS = require(‘aws-sdk’);exports.handler = async (event) => {
console.log(“event:”, JSON.stringify(event, undefined, 2));
const connectionId = event.requestContext.connectionId;
const route = event.requestContext.routeKey;
console.log(`ConnectionId = “${connectionId}” — Route = “${route}”`);
let body;

try {
switch (route) {
case “$connect”:
body = `Serverless Chat App Connected — ConnectionId “${connectionId}”`; // $connect
break;
case “sendMessage”:
const message = JSON.parse(event.body).message;
body = `Responding sendMessage with “${message}”`; // sendMessage
const callbackAPI = new AWS.ApiGatewayManagementApi({
apiVersion: ‘2018–11–29’,
endpoint:
event.requestContext.domainName + ‘/’ + event.requestContext.stage,
});
await callbackAPI
.postToConnection({ ConnectionId: connectionId, Data: body })
.promise();
break;
case “$disconnect”:
body = `Serverless Chat App Disconnected — ConnectionId “${connectionId}”`; // $disconnect
break;
case ‘$default’:
body = `Serverless Chat App Default Route`; // $default
break;
default:
throw new Error(`Unsupported route: “${connectionId}”`);
}
console.log(body);
return {
statusCode: 200,
body: JSON.stringify({
message: `Successfully finished operation: “${route}”`,
body: body
})
};
} catch (e) {
console.error(e);
return {
statusCode: 400,
body: JSON.stringify({
message: “Failed to perform operation.”,
errorMsg: e.message
})
};
}
};

Basically we handle all incoming request from Websocket API by looking the route key attributes. After that perform chat operations. To make simple I am not calling any database communications, instead we put body information about the operations.

E2E Test WebSocket API and Lambda Function with Incoming WebSocket API Event Json Object

We are going to E2E Test WebSocket API and Lambda Function with Incoming WebSocket API Event Json Object to perform crud operations.

Enter your websocket url and connect

  • wss://xxxx.execute-api.us-east-2.amazonaws.com/production

Connect and See Logs :
- Connecting to: wss://xx.execute-api.us-east-2.amazonaws.com/production
- Connection established

SendMessage:
{ “action”: “sendMessage”, “message”: “Hello from websocket !” }

See Logs :
▲ { “action”: “sendMessage”, “message”: “Hello from websocket !” }
▼ Processing sendMessage with “Hello from websocket !”

Lambda function respond incoming message from our websocket client. As you can see that
we have successfully tested our WebSocket API and Lambda functions
and finished Hands-on Lab: Build Serverless Chat App with a WebSocket API and Lambda.

Step by Step Design AWS Architectures w/ Course

I have just published a new course — AWS Lambda & Serverless — Developer Guide with Hands-on Labs.

In this course, we will learn almost all the AWS Serverless Services with all aspects. We are going to build serverless applications with using AWS Lambda, Amazon API Gateway, Amazon DynamoDB, Amazon Cognito, Amazon S3, Amazon SNS, Amazon SQS, Amazon EventBridge, AWS Step Functions, DynamoDB and Kinesis Streams. This course will be 100% hands-on, and you will be developing a real-world application with hands-on labs together and step by step.

Source Code

Get the Source Code from Serverless Microservices GitHub — Clone or fork this repository, if you like don’t forget the star. If you find or ask anything you can directly open issue on repository.

--

--

Mehmet Ozkaya
AWS Lambda & Serverless — Developer Guide with Hands-on Labs

Software Architect | Udemy Instructor | AWS Community Builder | Cloud-Native and Serverless Event-driven Microservices https://github.com/mehmetozkaya