Skip to main content
Skip table of contents

Publish and subscribe to notifications with AWS SNS

This guide explains how to integrate AWS SNS with a qibb flow using the function node and the official AWS SDK (https://www.npmjs.com/package/@aws-sdk/client-sns) imported as external module.

qibb_flow_aws_sns.png

Using the function node and AWS SDK

The examples will use the function node to integrate with AWS SNS using the AWS SDK. As a prerequisite, according function nodes should have the @aws-sdk/client-sns module installed and imported as awsSdkClientSns.

module_properties_in_function_node_aws_sns_client.png

Module in “Setup” tab of function node

In addition, the function node is expecting to have the following secrets stored in Space Secrets:

  • AWS_SNS_TOPIC_ARN

  • AWS_SNS_API_KEY

  • AWS_SNS_API_SECRET

  • AWS_SNS_TOPIC_REGION


Publishing SNS notifications

This example demonstrates how to publish a notification to an AWS SNS topic.

publish_sns_notification_to_topic.png

Publish SNS notification to a topic

Function Node Code Example for “Send SNS notification”

Function

Code

“On Start” Tab

Handles configuration of client on whenever the flow starts or restarts.

JS
// Import required classes from the AWS SDK v3 package
const { SNSClient } = awsSdkClientSns;

// Group configuration values in an object
this.config = {
    topicArn: global.get("SECRETS.AWS_SNS_TOPIC_ARN"), // e.g., "arn:aws:sns:us-west-2:811950790052:flow-sns-test"
    accessKey: global.get("SECRETS.AWS_SNS_API_KEY"),
    accessSecret: global.get("SECRETS.AWS_SNS_API_SECRET"),
    region: global.get("SECRETS.AWS_SNS_TOPIC_REGION")
};

// Create an SNS client instance and store it as a property of the node (this.client)
this.client = new SNSClient({
    region: this.config.region,
    credentials: {
        accessKeyId: this.config.accessKey,
        secretAccessKey: this.config.accessSecret
    }
});

// Define a helper function for safely stringifying the msg (avoiding circular references)
this.removeCircular = function () {
    const seen = new WeakSet();
    return (key, value) => {
        if (typeof value === 'object' && value !== null) {
            if (seen.has(value)) {
                return undefined;
            }
            seen.add(value);
        }
        return value;
    };
};

“On Message” Tab

Uses the client to send notification and passes response to output.

JS
// Import the PublishCommand from the AWS SDK v3 package
const { PublishCommand } = awsSdkClientSns;

// Retrieve the client and configuration from the node context (set in "On Setup")
const client = this.client;
const config = this.config;


async function publishNotification(){
    try {
        
        // Define the parameters for publishing a message
        const params = {
            Message: JSON.stringify(msg.payload),  // Convert your payload to a string
            TopicArn: config.topicArn,             // Your SNS topic ARN
            Subject: "SNS Test Notification"       // Optional: A subject line for endpoints (e.g., email)
        };

        // Create the PublishCommand using the 'new' keyword
        const command = new PublishCommand(params);

        // Send the command to SNS and await the response
        const data = await client.send(command);
        // Attach the response to msg.payload and send the message along the flow
        msg.payload = data;
        node.send(msg);
    } catch (error) {
        node.error("Error publishing message: " + error);
    }
}

// Execute the publishNotification function asynchronously
publishNotification();

// Return null since output is handled asynchronously via node.send()
return null;


Subscribe and receive SNS notifications

This example shows how to subscribe for an AWS SNS topic, setting up an HTTPS subscription pointing to an endpoint of the flow. AWS SNS will call the given endpoint immediately to confirm the subscription. Once the subscription is confirmed, AWS SNS will call this endpoint every time there is a new notification for that topic, and the flow will process the messages accordingly.

subscribe_to_sns_topic.png

Subscribe to SNS topic

process_incoming_SNS_notifications.png

Process incoming SNS notifications

Function Node for “Subscribe to SNS topic”

Function

Code

“On Start” Tab

Handles configuration of client on whenever the flow starts or restarts.

JS
// Import required classes from the AWS SDK v3 package
const { SNSClient } = awsSdkClientSns;

// Group configuration values in an object
this.config = {
    topicArn: global.get("SECRETS.AWS_SNS_TOPIC_ARN"), // e.g., "arn:aws:sns:us-west-2:811950790052:flow-sns-test"
    accessKey: global.get("SECRETS.AWS_SNS_API_KEY"),
    accessSecret: global.get("SECRETS.AWS_SNS_API_SECRET"),
    region: global.get("SECRETS.AWS_SNS_TOPIC_REGION"),
    endpointUrl: env.get("BASE_URL") + "/sns-subscription" // An opened HTTP endpoint of this flow for subscription confirmation
};

// Create an SNS client instance and store it as a property of the node (this.client)
this.client = new SNSClient({
    region: this.config.region,
    credentials: {
        accessKeyId: this.config.accessKey,
        secretAccessKey: this.config.accessSecret
    }
});

“On Message” Tab

Uses the stored client to setup a subscription for the SNS topic.

JS
// Import the SubscribeCommand from the AWS SDK v3 package
const { SubscribeCommand } = awsSdkClientSns;

// Retrieve the client and config from the node context (set in "On Setup")
const client = this.client;
const config = this.config;

// Define the subscription parameters
const params = {
    TopicArn: config.topicArn,  // Your SNS topic ARN
    Protocol: "https",          // Protocol to use for the subscription
    Endpoint: config.endpointUrl // Your Node-RED endpoint URL for receiving confirmation
};

async function setupSubscription(){
    try {
        // Create the subscription command using the 'new' keyword
        const command = new SubscribeCommand(params);

        // Send the command to SNS and wait for the response
        const data = await client.send(command);
        node.log("Subscription request created successfully. Data: " + JSON.stringify(data));

        // Attach the response to msg.payload and send the message along the flow
        msg.payload = data;
        node.send(msg);
    } catch (error) {
        node.error("Error creating subscription: " + error);
    }
}

// Execute the setupSubscription function asynchronously
setupSubscription();
// Return null since output is handled asynchronously via node.send()
return null;

Function Node for “Processing SNS Notification”

Function

Code

“On Start” Tab

No code required.

“On Message” Tab

Checks the type of the incoming message. If it has the type SubscriptionConfirmation, makes an HTTP request back to AWS SNS to confirm subscription.

If it has the type Notification, it parses and passes the message to the node output.

JS
//Check type of incoming SNS message
//Expects msg.payload has been parsed to JSON by another node beforehand.
switch (msg.payload.Type) {
    case "SubscriptionConfirmation":
        confirmSubscription();
        break;
    case "Notification":
        // Process and parse message
        processNotification();
        break;
}

// Function that parses and passes the notification to output
function processNotification() {
    msg.payload.Message = safeJSONParse(msg.payload.Message);
    node.send(msg);
}

// Function that calls the AWS SNS Subscribe URL to confirm subscription
async function confirmSubscription() {
    try {
        node.log("Received SubscriptionConfirmation. Confirming subscription...");
        const response = await fetch(msg.payload.SubscribeURL);
        const body = await response.text();
        node.log("Confirmed subscription.")
    } catch (error) {
        node.error("Error confirming subscription: " + error);
    }
}

// Helper function to safely parse JSON; returns original string if parsing fails
function safeJSONParse(input) {
    try {
        return JSON.parse(input);
    } catch (err) {
        return input;
    }
}

return null;
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.