Integrating AWS SNS with Lambda using JavaScript: A Deep Dive into the Code

Welcome to the enchanting realm of serverless architecture, where efficiency and scalability dance hand in hand. In this journey, we will explore a practical example of integrating AWS Simple Notification Service (SNS) with AWS Lambda using JavaScript. The provided code defines a Lambda function that serves as an API for managing SNS topics, subscriptions, and broadcasting messages. With this simple code example you will have the overall understanding of implementing SNS using AWS Lambda. Let’s delve into each function to understand its role and functionality.

1. Setting Up AWS SDK

Our journey begins with setting up the AWS SDK for JavaScript. We import the @aws-sdk/client-sns library and initialize an SNS client with a specific AWS region (ap-south-1). Additionally, we set a default SNS topic ARN, providing a starting point that can be tailored to your unique requirements.

import { SNSClient } from "@aws-sdk/client-sns";
import {
  CreateTopicCommand,
  SubscribeCommand,
  UnsubscribeCommand,
  PublishCommand,
  ListTopicsCommand,
  ListSubscriptionsByTopicCommand,
} from "@aws-sdk/client-sns";

const REGION = "ap-south-1";
const snsClient = new SNSClient({ region: REGION });
const SNS_TOPIC_ARN = 'arn:aws:sns:ap-south-1:XXXXXXXXXXX:simple-notify';

2. Lambda Function Handler

Our Lambda function, named handler, parses incoming JSON payloads and intelligently routes requests based on HTTP methods and paths. In this block of code you will find the routing technique based on HTTP Method and URL Path.

export const handler = async (event) => {
  let payload = null;
  try {
    payload = JSON.parse(event.body);
  } catch (err) {
    return buildResponse(401, { msg: 'Opps! Invalid payload supplied!' });
  }

  // Route the request based on HTTP method and path
  if (event.httpMethod === 'POST' && event.path === subscribePath) {
    return await subscribe(payload);
  } else if (event.httpMethod === 'POST' && event.path === topicsCreatePath) {
    return await createTopic(payload);
  } else if (event.httpMethod === 'DELETE' && event.path === subscribePath) {
    return await unsubscribe(payload);
  } else if (event.httpMethod === 'POST' && event.path === broadcastPath) {
    return await broadcast(payload);
  } else if (event.httpMethod === 'POST' && event.path === unsubscribePath) {
    return await unsubscribe(payload);
  } else if (event.httpMethod === 'GET' && event.path === topicsPath) {
    return await topics();
  } else if (event.httpMethod === 'GET' && event.path === subscriptionListPath) {
    let pload = {
      topicArn: event.queryStringParameters ? event.queryStringParameters.topicArn || SNS_TOPIC_ARN : SNS_TOPIC_ARN,
    };
    return await subscriptions(pload);
  } else {
    return createResponse(401, { msg: 'Opps! You are unauthorized!', event: event });
  }
};

3. Handling Subscriptions

SNS Topic Creation

Crafting a new SNS topic is not an intricate process. The createTopic function orchestrates the functionality seamlessly. Just provide a payload with a topicName, and witness as the parameters elegantly come together, placing the CreateTopicCommand in the spotlight.

async function createTopic(payload) {
  if (!payload || !payload.topicName) return buildResponse(403, { msg: 'Missing param: topicName' });

  const params = {
    Name: payload.topicName,
  };

  try {
    const data = await snsClient.send(new CreateTopicCommand(params));
    return createResponse(200, data);
  } catch (err) {
    return createResponse(403, err);
  }
};

SNS Topic Subscription

The subscribe function is your invitation to the notification party. It gracefully handles subscriptions by expecting a payload with an endPoint (e.g., a dazzling email address) and an optional topicArn. Armed with these details, it constructs the necessary parameters and orchestrates a beautiful SubscribeCommand symphony.

async function subscribe(payload) {
  if (!payload || !payload.endPoint) return buildResponse(403, { msg: 'Missing param: endPoint' });

  const params = {
    Protocol: 'email',
    TopicArn: payload.topicArn || SNS_TOPIC_ARN,
    Endpoint: payload.endPoint, // valid email id
  };

  try {
    const data = await snsClient.send(new SubscribeCommand(params));
    return createResponse(200, data);
  } catch (err) {
    return createResponse(403, err);
  }
};

SNS Topic Un-subscription

Unsubscribing is easy just like that. It accepts a payload with a subsArn, constructs parameters, and orchestrates the command to set you free from unwanted notifications.

async function unsubscribe(payload) {
  if (!payload || !payload.subsArn) return buildResponse(403, { msg: 'Missing param: subsArn' });

  const params = {
    SubscriptionArn: payload.subsArn,
  };

  try {
    const data = await snsClient.send(new UnsubscribeCommand(params));
    return createResponse(200, data);
  } catch (err) {
    return createResponse(403, err);
  }
};

4. Broadcasting the Message

Broadcasting a message is an elegant affair, and the broadcast function knows it well. With a payload carrying a meaningful message and an optional topicArn, it crafts the parameters and orchestrates the PublishCommand to spread the news far and wide.

async function broadcast(payload) {
  if (!payload || !payload.message) return buildResponse(403, { msg: 'Missing param: message' });

  const params = {
    Message: payload.message.trim(),
    TopicArn: payload.topicArn || SNS_TOPIC_ARN,
  };

  try {
    const data = await snsClient.send(new PublishCommand(params));
    return createResponse(200, data);
  } catch (err) {
    return createResponse(403, err);
  }
};

5. Listing All SNS Topics

The topics function is your telescope into the cosmos of SNS topics. It uses the ListTopicsCommand to bring you a list of registered topics.

async function topics() {
  try {
    const data = await snsClient.send(new ListTopicsCommand({}));
    return createResponse(200, data);
  } catch (err) {
    return createResponse(403, err);
  }
};

6. Listing Subscriptions by SNS Topic

Embark on a journey of exploring subscriptions using the subscriptions function. With a payload that includes a topicArn (or a default if not provided), this function adeptly employs the ListSubscriptionsByTopicCommand to unveil the list of subscribers associated with your topic.

async function subscriptions(payload) {
  try {
    const params = { TopicArn: payload.topicArn || SNS_TOPIC_ARN };
    const data = await snsClient.send(new ListSubscriptionsByTopicCommand(params));
    return createResponse(200, data);
  } catch (err) {
    return createResponse(403, err);
  }
};

7. Constructing HTTP Response

The createResponse artfully standardizes the HTTP response format, ensuring our communication with the world is clear and harmonious.

function createResponse(statusCode, body) {
  return {
    statusCode: statusCode,
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  };
}

8. Deploying and Testing

As we set sail to deploy our Lambda function, remember these steps:

  1. Package the Lambda function using npm pack.
  2. Upload the generated zip file to AWS Lambda.
  3. Configure an API Gateway to trigger the Lambda function.
  4. Test the API by sending HTTP requests to the configured endpoints.

Conclusion

Integrating AWS SNS with Lambda provides a flexible and scalable solution for handling notifications and events in your serverless applications. This example code serves as a starting point, and you can extend and customize it based on your specific requirements. As you delve deeper into the AWS ecosystem, consider exploring additional features and optimizations offered by SNS and Lambda to enhance your serverless architecture.

Scroll to Top