Node.js - Amazon Web Services support for TypeScript
AWS Lambda
Lambda services allow executing some source code on the cloud. The execution can be set to be triggered by some AWS events. Lambda functions can be deployed using several deployment frameworks. The supported deployment frameworks are listed on this page. When a lambda function is created and its runtime is Node.js, the TypeScript and Frameworks extension is responsible for linking the lambda objects and their triggers with the TypeScript handler functions.
Basic example
Let us consider a source code defining a lambda function that has two triggers: an SQS queue and an API Gateway. The lambda function has a nodejs runtime and the handler function is given by the handler function fullname. If the lambda function is deployed using a supported deployment framework (such as CloudFormation), the analysis will create a lambda function, an SQS receiver, and an API Gateway objects. Each of these objects has a runtime property (nodejs) and a handler property with the function fullname. If the current extension finds a TypeScript function matching the handler fullname a link to that function will be added from the lambda function, the SQS queue, and the API Gateway objects.
Lambda invocation using SDK
The SDK provides APIs to execute (i.e. invoke) lambda function. The following APIs are supported:
- invoke method of the Lambda “aws-sdk” client of the SDK V2
- InvokeCommand of the SDK V3
Example
When analyzing the following source code:
import * as AWS from 'aws-sdk'
// Set region
function my_invoke(){
AWS.config.update({region: 'REGION'});
var lambda = new AWS.Lambda();
var params = {
FunctionName: 'mylambda', /* required */
//...
};
lambda.invoke(params, function(err, data) {
//...
});
}
a call to AWS lambda function object named mylambda is created. com.castsoftware.wbslinker links that call to lambda object to AWS Lambda Function objects having the same name:
AWS SNS
The following APIs are supported:
SDK V2
The publish and subscribe methods of the SNS client are supported:
import AWS from 'aws-sdk'
const snsClient = new AWS.SNS({...})
snsClient.publish(...)
snsClient.subscribe(...)
SDK V3
The PublishCommand and SubscribeCommand (which are used with the snsClient.send method) are supported:
import { SNSClient, PublishCommand, SubscribeCOmmand } from "@aws-sdk/client-sns";
const snsClient = new SNSClient({ region: REGION });
snsClient.send(new PublishCommand(params))
snsClient.send(new SubscribeCommand(params))
Detailed support
A Nodejs SNS Publisher object is created whenever a publication to a topic is found by the analyzer. Its name is that of the topic. For subscriptions, a Nodejs SNS Subscriber object is created. Its name is that of the topic. Then for each supported protocol, an object is created with a callLink from the subscriber to that object. The following protocols are supported:
Protocol | Object created | Object name |
---|---|---|
Nodejs Email | an Email (the email addresses are not evaluated) | |
sms | Nodejs SMS | an SMS (the SMS numbers are not evaluated) |
http/https | Nodejs Post Service | the url (evaluated from the endpoint) |
sqs | Nodejs AWS Simple Queue Service Publisher | the name of the queue (evaluated from the endpoint) |
lambda | Nodejs Call to AWS Lambda Function | the name of the lambda function (evaluated from the endpoint) |
Example
When analyzing the following source code:
import {CreateTopicCommand, SNSClient, SubscribeCommand, PublishCommand } from "@aws-sdk/client-sns";
const REGION = "REGION"; //e.g. "us-east-1"
// Create SNS service object.
const snsClient = new SNSClient({ region: REGION });
function my_subscribe(protocol, topic_arn, endpoint){
const params = {
Protocol: protocol,
TopicArn: topic_arn, //TOPIC_ARN
Endpoint: endpoint,
};
const data = await snsClient.send(new SubscribeCommand(params));
};
function subcribe_to_foo_topic(){
const topic_arn = 'arn:aws:sns:us-east-2:123456789012:foo_topic';
my_subscribe("email", topic_arn, "EMAIL_ADDRESS")
my_subscribe("sms", topic_arn, "007")
my_subscribe("lambda", topic_arn, "fooarn:function:lambda_name:v2")
my_subscribe("sqs", topic_arn, "https://sqs.us-east-2.amazonaws.com/123456789012/foo_queue")
my_subscribe("http", topic_arn, "http://foourl")
}
function publish_to_foo_topic(){
const params = {
Message: "MESSAGE_TEXT", // MESSAGE_TEXT
TopicArn: 'arn:aws:sns:us-east-2:123456789012:foo_topic'
};
const data = await snsClient.send(new PublishCommand(params));
}
This code will produce the following result:
AWS S3
The following links are created:
Link Type | Methods from SDK V2 s3client
|
Methods from SDK V3 s3client
|
Commands from SDK V3 imported from '@aws-sdk/client-s3' |
---|---|---|---|
No Link |
|
|
|
callLink |
|
|
|
useInsertLink |
|
|
|
useDeleteLink |
|
|
|
useSelectLink |
|
|
|
useUpdateLink |
|
|
|
Example
This code will create an S3 Bucket named “MyBucket” and a useInsert link to that bucket:
foo.ts
// Load the AWS SDK for Node.js
import * as AWS from 'aws-sdk'
// Set the region
AWS.config.update({region: 'REGION'});
// Create S3 service object
s3 = new AWS.S3({apiVersion: '2006-03-01'});
// Create the parameters for calling createBucket
var bucketParams = {
Bucket : "MyBucket",
ACL : 'public-read'
};
// call S3 to create the bucket
s3.createBucket(bucketParams, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Location);
}
});
params = {
// ...
Bucket: "MyBucket"
};
s3.putObject(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
This code will produce the following result:
AWS SQS
Supported APIs
API | Methods from SDK V2 sqs client |
Commands from SDK V3 imported from '@aws-sdk/client-sqs' |
---|---|---|
Publish |
|
|
Receive |
|
|
Example
This code will publish a message into the “SQS_QUEUE_URL” queue:
import * as AWS from "aws-sdk";
AWS.config.update({ region: 'REGION' });
const sqs = new AWS.SQS({apiVersion: '2012-11-05'});
const queueUrl = "SQS_QUEUE_URL"
const params = {
MessageBody: "This is a message",
QueueUrl: queueUrl,
MaxNumberOfMessages: 1,
VisibilityTimeout: 0,
};
class Foo {
sendMessage(){
sqs.sendMessage(params, function (err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.MessageId);
}
});
}
}
This code will receive a message from the queue “SQS_QUEUE_URL”:
import * as AWS from "aws-sdk";
AWS.config.update({ region: 'REGION' });
const sqs = new AWS.SQS({apiVersion: '2012-11-05'});
const queueUrl = "SQS_QUEUE_URL"
const params = {
QueueUrl: queueUrl,
MaxNumberOfMessages: 1,
VisibilityTimeout: 0,
};
export class SqsReciver {
constructor() {
this.reciver();
}
private reciver(): void {
sqs.receiveMessage(params, (err, data) => {
// do something
});
}
}
This code will produce the following result:
When the evaluation of the queue name fails, a Node.js AWS SQS Unknown Publisher (or Receiver) will be created.
AWS DynamoDB
See DynamoDB support for Node.js source code - TypeScript.
AWS X-Ray
AWS X-Ray encapsulates AWS method calls in order to provide status and load status.
Example
This code will encapsulate AWS SDK then create a dynamoDB instance, and a Table instance:
import AWSXRay from 'aws-xray-sdk-core'
import AWS from 'aws-sdk'
const AWS = AWSXRay.captureAWS(AWS) // Encapsulate AWS SDK
const DDB = new AWS.DynamoDB({ apiVersion: "2012-10-08" }) // use AWS as usual
const { v1: uuidv1 } = require('uuid');
// environment variables
const { TABLE_NAME, ENDPOINT_OVERRIDE, REGION } = process.env
const options = { region: REGION }
AWS.config.update({ region: REGION })
if (ENDPOINT_OVERRIDE !== "") {
options.endpoint = ENDPOINT_OVERRIDE
}
const docClient = new AWS.DynamoDB.DocumentClient(options)
// response helper
const response = (statusCode, body, additionalHeaders) => ({
statusCode,
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', ...additionalHeaders },
})
function addRecord(event) {
let usernameField = {
"cognito-username": getCognitoUsername(event)
}
// auto generated date fields
let d = new Date()
let dISO = d.toISOString()
let auto_fields = {
"id": uuidv1(),
"creation_date": dISO,
"lastupdate_date": dISO
}
//merge the json objects
let item_body = {...usernameField, ...auto_fields, ...JSON.parse(event.body) }
console.log(item_body);
//final params to DynamoDB
const params = {
TableName: TABLE_NAME,
Item: item_body
}
return docClient.put(params)
}
This code will produce the following result:
Known limitations
- The use of AWS.SQS with promises is not supported. For instance, no link would be created between the receiver and the handler function defined in .then() call in the following source code:
this.sqs.receiveMessage(params).promise().then( () => {})
- If the queueName is set using the createQueue API, the evaluation of the queue name will fail.
- Use of access points is not supported