Setting up AWS SDK for SNS/SQS in Node.js

May 01, 2020

Version 3 of the JavaScript SDK now splits up the package into smaller modules. This way, you only download what you need and reduce your file size. Packages are downloaded in the form of:

$ npm install @aws-sdk/client-«package-name»

If you can’t remember the name of the package, simply search to return a list of names:

$ npm install @aws-sdk/client-
NAME                      | DESCRIPTION          |
@aws-sdk/client-s3        | AWS SDK for…         |
@aws-sdk/client-sts       | AWS SDK for…         |
@aws-sdk/client-lex-runti | AWS SDK for…         |
me-service                |                      |
@aws-sdk/client-transcrib | AWS SDK for…         |
e-streaming               |                      |
@aws-sdk/client-s3-contro | AWS SDK for…         |
l                         |                      |
@aws-sdk/client-mediastor | AWS SDK for…         |
e-data                    |                      |
@aws-sdk/client-cognito-i | AWS SDK for…         |
dentity                   |                      |

You can use ES6-style imports for modules. Note: you can’t mix and match both style of imports.

{ SQSClient } = require("@aws-sdk/client-sqs)";  // old way
import { SQSClient } from "@aws-sdk/client-sqs"; // new way

// Be sure to add this to "/package.json" to use ES6 imports
{
  "type": "module",
}

SQS

You’ll need a client object to send your commands.

/**
 * Save file to somewhere like "/libs/sql-client.js"
 * to reuse an existing client object.
 */
import { SQSClient } from "@aws-sdk/client-sqs";
const REGION = "us-west-1";
const client = new SQSClient({ region: REGION });
export { client }

ListQueuesCommand

ListQueuesCommand requires you to supply an empty object as its default argument.

import { ListQueuesCommand } from "@aws-sdk/client-sqs";
import { client } from "./lib/sqs-client.js";

const listQueues = async () => {
  try {
    const data = await client.send(new ListQueuesCommand({}));
    console.log("Success", data);
    return data;
  } catch (err) {
    console.error(err, err.stack);
  }
};
listQueues();

Run the file at the terminal with node «file-name».js and you’ll receive the following response:

$ node list-command.js
{
  '$metadata': {
    httpStatusCode: 200,
    requestId: '59314882-ba58-5429-a820-a8aec8f020f2',
    extendedRequestId: undefined,
    cfId: undefined,
    attempts: 1,
    totalRetryDelay: 0
  },
  NextToken: undefined,
  QueueUrls: [ 'https://sqs.us-west-1.amazonaws.com/248874545298/«QueueName»' ]
}

You can grab the QueueUrl here, or use GetQueueUrlCommand if you know the name of your queue.

import { GetQueueUrlCommand } from "@aws-sdk/client-sqs";
import { client } from  "./lib/sqs-client.js";

const params = { QueueName: "QUEUE_NAME" };

const queueName = async () => {
  try {
    const data = await client.send(new GetQueueUrlCommand(params));
    console.log("Success", data);
    return data;
  } catch (err) {
    console.log("Error", err);
  }
};
queueName();

SendMessageCommand

You’ll need the QueueUrl from above to send and receive messages from a queue. SendMessageCommand accepts a single object that implements the SendMessageCommandInput interface. If you’re not familiar with TypeScript, it means your object must match the following signature:

  • MessageBody - must be a string type. This means you must JSON.stringify() any JSON object you want to pass in here. The documentation states that “a message can include only XML, JSON, and unformatted text”, but raw JSON objects seem to fail (could be a bug).
  • MessageAttributes - an optional object intended to be used as metadata (i.e. supplementary info about more important stuff in MessageBody). Can have up to 10 nested objects called attributes.

    • Although even the documentation affirms its use as “structured metadata (such as timestamps, geospatial data, signatures, and identifiers)”, AWS’s official example switches MessageBody and MessageAttributes.
  • QueueUrl - a required parameter of string type. This is where the messages are sent.

The example below uses JSON.stringify() to pass a JSON object to MessageBody.

import { SendMessageCommand } from  "@aws-sdk/client-sqs";
import { client } from  "./lib/sqs-client.js";
import { getQueue } from ".lib/sqs-listqueues.js"; // grab queue URL

// Example using a credit card transaction.
body = {
  TransactionId: "758191",
  CustomerId: "CID_132",
  CustomerEmail: "foo@bar.com",
  Amount: 50.00
}

const params = {
  MessageBody: JSON.stringify(body)
};

const sendMessage = async () => {
  try {
    const url = await getQueue();
    console.log(url);
    params.QueueUrl = url; // Add queue URL to params object.
    const data = await client.send(new SendMessageCommand(params));
    console.log(data);
    return data
  } catch (err) {
    console.error(err, err.stack);
  }
};

sendMessage();

ReceiveMessageCommand, DeleteMessageCommand

Messages retrieved from the queue should be deleted once read, to prevent other consumers from reading a duplicate message.

ReceiveMessageCommand accepts an input parameter that implements ReceiveMessageCommandInput interface. The object has the following properties:

  • AttributeNames - optional, returns a list of attributes along with each message. Possible values are:

    • All - returns all values.
    • ApproximateFirstReceiveTimestamp - time when message was first received from queue (in milliseconds).
    • ApproximateReceiveCount - how many times message was previously retrieved.
    • SenderId - IAM user or role ID.
    • SentTimestamp - time when message was sent to queue (in milliseconds).
  • MaxNumberOfMessages - optional, defaults to 1. Valid values are from 1 to 10.
  • QueueUrl - URI of queue where messages are retrieved from.
  • VisibilityTimeout - optional, how long (in seconds) to hide messages from subsequent requests.
  • WaitTimeSeconds - optional, how long the call waits for a message to be available in the queue (if empty).
import { ReceiveMessageCommand, DeleteMessageCommand } from "@aws-sdk/client-sqs";
import { client } from "./lib/sqs-getclient.js";
import { getQueue } from "./lib/sqs-listqueues.js";

const params = {
  AttributeNames: ["All"],
  MaxNumberOfMessages: 1
};

const receiveDelete = async () => {
  try {
    const url = await getQueue();
    params.QueueUrl = url;
    const data = await client.send(new ReceiveMessageCommand(params));
    console.log(data);
    if (data.Messages) {
        
      // object used to delete retrieved message
      let delParams = {
        QueueUrl: url,
        // ReceiptHandle is the identifier used
        // to delete a specific message
        ReceiptHandle: data.Messages[0].ReceiptHandle
      };
      
      // Print retrieved message.
      console.log(data.Messages[0]?.Body);
      
      // Delete retrieved message
      try {
        const response = await client.send(new DeleteMessageCommand(delParams));
        console.log("Message deleted:", response);
      } catch (err) {
        console.log("Error", err);
      }
      
    } else {
      console.log("receive error");
    }
    
  } catch (err) {
    console.error(err, err.stack);
  }
};

receiveDelete();

Profile picture

Written by Samuel Moon who lives and works in Los Angeles building useful things. Check out my GitHub.