In this tutorial, we will learn how to develop a serverless real-time application using Node.js 18, AWS SAM, and AWS SDK v3 with WebSockets. By the end of this tutorial, you will be able to build a chat application that can send and receive messages in real-time.

Prerequisites:

  • Basic knowledge of JavaScript and Node.js
  • Familiarity with AWS services
  • An AWS account

Table of Contents:

  1. Setting Up the Environment
  2. Creating the Lambda Function
  3. Configuring API Gateway
  4. Implementing WebSocket in the Client
  5. Testing the Application

Setting Up the Environment

1. Install Node.js 18 and npm (skip if already installed): Visit https://nodejs.org/en/download/ to download and install Node.js 18. This will also install npm, the package manager for Node.js.

2. Install the AWS CLI: Follow the instructions at https://aws.amazon.com/cli/ to install and configure the AWS CLI.

3. Install AWS SAM CLI: Follow the instructions at https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html to install and configure the AWS SAM CLI.

Creating the Lambda Function

Initialize a new AWS SAM application: Run the following command to create a new AWS SAM application using the Node.js 18.x template:

sam init --runtime nodejs18.x --name <your_app_name>
cd <your_app_name>

Install the dynamodb package using the following command:

npm install @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb

Open 'template.yaml' and add the following configuration to define the Lambda function and WebSocket API:

Resources:
  MyWebSocketFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: .
      Handler: app.handler
      Runtime: nodejs18.x
      Events:
        Connect:
          Type: Api
          Properties:
            Path: /connect
            Method: ANY
            RestApiId: !Ref MyWebSocketApi
        Disconnect:
          Type: Api
          Properties:
            Path: /disconnect
            Method: ANY
            RestApiId: !Ref MyWebSocketApi
        Default:
          Type: Api
          Properties:
            Path: /default
            Method: ANY
            RestApiId: !Ref MyWebSocketApi

  MyWebSocketApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      DefinitionBody:
        swagger: '2.0'
        info:
          title: My WebSocket API
        schemes:
          - wss
        basePath: /
        paths:
          /connect:
            x-amazon-apigateway-any-method:
              responses: {}
          /disconnect:
            x-amazon-apigateway-any-method:
              responses: {}
          /default:
            x-amazon-apigateway-any-method:
              responses: {}
  ConnectionsTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: your_table_name
      AttributeDefinitions:
        - AttributeName: connectionId
          AttributeType: S
      KeySchema:
        - AttributeName: connectionId
          KeyType: HASH
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1

Create a new file named 'app.js' in the root directory of your project and add the following code:

const { DynamoDBClient, PutItemCommand, DeleteItemCommand } = require('@aws-sdk/client-dynamodb');
const { marshall, unmarshall } = require('@aws-sdk/util-dynamodb');

const REGION = 'your_region';
const TABLE_NAME = 'your_table_name';
const dynamoDbClient = new DynamoDBClient({ region: REGION });

exports.handler = async (event) => {
  const connectionId = event.requestContext.connectionId;
  const eventType = event.requestContext.eventType;

  if (eventType === 'CONNECT') {
    await addConnection(connectionId);
  } else if (eventType === 'DISCONNECT') {
    await deleteConnection(connectionId);
  } else {
    // Handle default event
  }
  
  return {
    statusCode: 200,
  };
};

async function addConnection(connectionId) {
  const params = {
    TableName: TABLE_NAME,
    Item: marshall({ connectionId }),
  };
  await dynamoDbClient.send(new PutItemCommand(params));
}

async function deleteConnection(connectionId) {
  const params = {
    TableName: TABLE_NAME,
    Key: marshall({ connectionId }),
  };
  await dynamoDbClient.send(new DeleteItemCommand(params));
}

Configuring API Gateway

Deploy your AWS SAM application by running the following command:

sam build
sam deploy --guided

Follow the prompts and take note of the WebSocket URL provided after the deployment is complete.

Implementing WebSocket in the Client

Create an 'index.html' file and add the following code to implement WebSocket:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Real-time Chat Application</title>
</head>
<body>
    <div>
        <textarea id="chat" readonly></textarea>
    </div>
    <div>
        <input type="text" id="message" />
        <button onclick="sendMessage()">Send</button>
    </div>
    <script>
        const wsUrl = 'YOUR_WEBSOCKET_URL';
        const websocket = new WebSocket(wsUrl);

        websocket.onopen = () => {
            console.log('Connected');
        };

        websocket.onmessage = (event) => {
            const chatArea = document.getElementById('chat');
            chatArea.value += '\n' + event.data;
        };

        function sendMessage() {
            const messageInput = document.getElementById('message');
            const message = messageInput.value;
            websocket.send(message);
            messageInput.value = '';
        }
    </script>
</body>
</html>

Replace 'YOUR_WEBSOCKET_URL' with the WebSocket URL you received after deploying the AWS SAM application.

Testing the Application

Serve the 'index.html' file using a local web server, such as the 'http-server' package, or upload it to an S3 bucket to host it as a static website. Open the page in multiple browser windows, and test the real-time chat functionality by sending messages between the instances.

Conclusion:

In this tutorial, we have covered the process of developing a serverless real-time chat application using Node.js 18, AWS SAM, AWS SDK v3, and WebSockets. We've demonstrated how to set up the environment, create a Lambda function, configure API Gateway, implement WebSocket functionality in the client, and test the application. By following these steps, you have gained valuable experience in leveraging AWS services and the Serverless Application Model to create scalable and cost-effective real-time applications.

This foundation can be further built upon to create more sophisticated real-time applications, such as collaborative editing tools, live data dashboards, and online gaming platforms. As you continue to explore the potential of serverless architectures and real-time applications, consider diving deeper into AWS services, such as AWS AppSync for GraphQL-based real-time data synchronization or Amazon Kinesis for large-scale real-time data streaming and processing. The possibilities are vast, and the skills you've acquired in this tutorial will undoubtedly help you create powerful, real-time serverless applications.

Related posts

Tell us about your goals.

Every goal is a milestone waiting to be achieved. Share your vision with us, and let's turn aspirations into accomplishments together. We're all ears, ready to make your goals our mission.

Tell Us Where You Want To Be…

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.