Node.js - Amazon Web Services CDK V2 support for TypeScript


Introduction

This section describes the support for the AWS CDK V2 framework. AWS CDK (Cloud Development Kit) is a framework that lets you define and provision AWS infrastructure.

Objects

Icon Description
AWS Lambda Function
NodeJS Call to AWS Lambda Function
NodeJS Call to AWS Unknown Lambda Function
NodeJS AWS SNS Publisher
NodeJS AWS Unknown SNS Publisher
NodeJS AWS SNS Subscriber
NodeJS AWS Unknown SNS Subscriber
NodeJS AWS SQS Publisher
NodeJS AWS Unknown SQS Publisher
NodeJS AWS SQS Receiver
NodeJS AWS Unknown SQS Receiver
NodeJS Email
NodeJS SMS
TypeScript Post http service
TypeScript Get http service
AWS GET API Gateway
AWS PUT API Gateway
AWS POST API Gateway
AWS DELETE API Gateway
AWS ANY API Gateway
AWS PATCH API Gateway

List of supported APIs

A partial support is provided for all the following APIs:

  • aws-cdk-lib/aws-lambda.Function
  • aws-cdk-lib/aws-lambda-nodejs.NodejsFunction
  • aws-cdk-lib/aws-lambda-event-sources.SqsEventSource
  • aws-cdk-lib/aws-lambda-event-sources.SnsEventSource
  • aws-cdk-lib/aws-lambda-event-sources.S3EventSource
  • aws-cdk-lib/aws-lambda-event-sources.S3EventSourceV2
  • aws-cdk-lib/aws-lambda-event-sources.DynamoEventSource
  • aws-cdk-lib/aws-apigatewayv2.HttpApi.addRoutes
  • aws-cdk-lib/aws-apigateway.RestApi
  • aws-cdk-lib/aws-apigateway.LambdaRestApi
  • aws-cdk-lib/aws-sns.Topic.addSubscription
  • aws-cdk-lib/aws-sns-subscriptions.LambdaSubscription
  • aws-cdk-lib/aws-sns-subscriptions.UrlSubscription
  • aws-cdk-lib/aws-sns-subscriptions.SqsSubscription
  • aws-cdk-lib/aws-sns-subscriptions.EmailSubscription
  • aws-cdk-lib/aws-sns-subscriptions.SmsSubscription
  • aws-cdk-lib/aws-s3.Bucket.addEventNotification
  • aws-cdk-lib/aws-s3-notifications.LambdaDestination
  • aws-cdk-lib/aws-s3-notifications.SqsDestination
  • aws-cdk-lib/aws-s3-notifications.SnsDestination

Physical name of the AWS service instances

When setting up a service (such as a Lambda) with AWS CDK, one can provide an explicit physical name for the instance of the service (for example, using functionName for a Lambda).

When an explicit physical name is provided, and the service type is supported, this analyzer creates an object whose name exactly matches the provided physical name.

Often, the physical name is not provided and is automatically generated by AWS based on:

  • the construct ID passed to the service constructor
  • the stack name in which the service is defined
  • a hash/suffix that guarantees uniqueness

In this case, for supported services, this extension creates a corresponding object named using the following pattern:

{StackName}-{ConstructID}-{}

The trailing ‘-{}’ represents the Hash value that cannot be predicted.

The {StackName} is inferred from:

  • the stackName property provided in the StackProps during stack instantiation

If stackName is not specified, then:

  • {StackName} defaults to the Stack ID (the second argument of the stack constructor).

In the following example, a Lambda function is created without providing an explicit physical name (the functionName property is commented out).

Therefore, the generated Lambda physical name will be FooStack-LambdaConstructID-{}.

// lib/lambda-stack.ts
import * as lambda from "aws-cdk-lib/aws-lambda";
export class LambdaStack extends cdk.Stack {
     constructor(scope: Construct, id: string, props?: cdk.StackProps) {
         super(scope, id, props);
         const fn = new lambda.Function(this, "LambdaConstructID", {
             runtime: lambda.Runtime.NODEJS_18_X, 
             handler: "index.handler",
             code: mycode, 
             //functionName: "FooLambda"
             })
         
         this.mylambda_name = fn.functionName
             
     }
}
// index.ts
import { LambdaStack } from './lib/lambda-stack';

const app = new App();
new LambdaStack(app, 'StackId', {
    stackName: 'FooStack'
});

Lambda support

Supported APIs

A basic support for the following API is provided:

  • aws-cdk-lib/aws-lambda.Function
  • aws-cdk-lib/aws-lambda-nodejs.NodejsFunction

Detailed support for aws-cdk-lib/aws-lambda.Function

When an instantiation of aws-cdk-lib/aws-lambda.Function is found in the analyzed source code, an AWS Lambda Function object is created. It has a properties storing the handler path and the runtime. The linking from the lambda function to the handler function is then carried out by one of the following extensions (depending on the runtime):

Runtime Extension
java com.castsoftware.awsjavaexternal link
dotnet com.castsoftware.awsdotnetexternal link
python com.castsoftware.pythonexternal link
nodejs com.castsoftware.nodejsexternal link (when the handler is written in .js)

com.castsoftware.typescriptexternal link (when the handler is written in .ts)

Note that the link to the handler function only works when the code property is provided via lambda.Code.fromAsset pointing to a directory, not to a pre-compressed ZIP file.

When analyzing the following source code:

import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';

export class LambdaLayerStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const fn = new lambda.Function(this, 'LambdaConstructID', {
        runtime: lambda.Runtime.NODEJS_LATEST,
        code: lambda.Code.fromAsset('resources/lambda'),
        handler: 'index.handler',
        functionName: 'FooFunction'    
      }
    );
  }
}

an AWS Lambda Function object named FooFunction is created with link to the handler function (assuming that the code of the handler function is also analyzed) as shown in the following snippet:

Known limitations

  • for nodejs or python runtime, the link to the handler will be correctly created only when the code is provided through lambda.Code.fromAsset.
    In other cases, this extension will try to find the best match but may not find the right handler or select a wrong handler
  • for nodejs or python runtime, the lambda.Code.fromAsset should not take a compressed file
  • code provided using lambda.Code.fromInLine is not analyzed

Detailed support for aws-cdk-lib/aws-lambda-nodejs.NodejsFunction

When an instantiation of aws-cdk-lib/aws-lambda-nodejs.NodejsFunction is found in the analyzed source code, an AWS Lambda Function object is created. It has a properties storing the handler path and the runtime. A link to the handler function is created.

For example, when analyzing the following source code:

import * as path from "path";
import { Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import * as lambda from "aws-cdk-lib/aws-lambda";

export class MyStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    new NodejsFunction(this, "MyFunction", {
      runtime: lambda.Runtime.NODEJS_18_X,
      entry: path.join(__dirname, "../lambda/handler.ts"),
      handler: "handler",
      functionName: "FooPhysicalName"
    });
  }
}

an AWS Lambda Function object named FooPhysicalName is created with link to the handler function (assuming that the code of the handler function is also analyzed) as shown in the following snippet:

Detailed support of lambda Event Source

Whenever the source code contains a call to the addEventSource API of an instance of a lambda Function (either aws-cdk-lib/aws-lambda.Function or aws-cdk-lib/aws-lambda-nodejs.NodejsFunction), the first argument of the addMethod API is checked. A support is provided if that argument is an instance of one of the following EventSource:

  • aws-cdk-lib/aws-lambda-event-sources.SqsEventSource
  • aws-cdk-lib/aws-lambda-event-sources.SnsEventSource
  • aws-cdk-lib/aws-lambda-event-sources.S3EventSource
  • aws-cdk-lib/aws-lambda-event-sources.S3EventSourceV2
  • aws-cdk-lib/aws-lambda-event-sources.DynamoEventSource

Detailed support for each EventSource is given in the following subsections.

SqsEventSource

When the call to the addEventSource APIa take an instance of aws-cdk-lib/aws-lambda-event-sources.SqsEventSource, a NodeJS AWS SQS Receiver (or a NodeJS AWS Unknown SQS Receiver if the evaluation of the bucket name fails) object is created with a callLink to the lambda.

For example, when analyzing the following source code:

import * as cdk from 'aws-cdk-lib';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as sqs from 'aws-cdk-lib/aws-sqs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { SqsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
import { Construct } from 'constructs';

export class SqsLambdaStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Lambda function
    const fn = new lambda.Function(this, 'MyLambda', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('resources/lambda')
    });
    
    const queue = new sqs.Queue(this, 'MyQueue', 
     { queueName: 'fooqueue',}
    );
    fn.addEventSource(new SqsEventSource(queue));
  }
}

you will get the following result:

SnsEventSource

When the call to the addEventSource APIa take an instance of aws-cdk-lib/aws-lambda-event-sources.SnsEventSource, a NodeJS AWS SNS Subscriber (or a NodeJS AWS SNS Subscriber if the evaluation of the bucket name fails) object is created with a callLink to the lambda.

For example, when analyzing the following source code:

import * as cdk from 'aws-cdk-lib';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { SnsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
import { Construct } from 'constructs';

export class SqsLambdaStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Lambda function
    const fn = new lambda.Function(this, 'MyLambda', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('resources/lambda')
    });
    
    const topic = new sns.Topic(this, 'MyTopic', {
      topicName: 'fooTopic',
    });
    fn.addEventSource(new SnsEventSource(topic));
  }
}

you will get the following result:

S3EventSource and S3EventSourceV2

When the call to the addEventSource API takes an instance of aws-cdk-lib/aws-lambda-event-sources.S3EventSource (or aws-cdk-lib/aws-lambda-event-sources.S3EventSourceV2), a property Names of s3 events triggering the lambda is added to the lambda. This property saves the name of the S3 bucket as well event type that would trigger the lambda. The analyzer creates a call link to the lambda function object from all callables linked to the given bucket through a link of matching type. The following table tells which link type will match which event type (in the table, the * matches any string).

event type matching link types
No event type all
OBJECT_CREATED useInsert, useUpdate
OBJECT_CREATED_* useInsert, useUpdate
OBJECT_REMOVED useDelete
OBJECT_REMOVED_* useDelete
other event types None

For example, when analyzing the following source code:

import * as cdk from 'aws-cdk-lib';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { S3EventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
import { Construct } from 'constructs';

import * as s3 from 'aws-cdk-lib/aws-s3';

export class SqsLambdaStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Lambda function
    const fn = new lambda.Function(this, 'MyLambda', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('resources/lambda')
    });
    
    const bucket = new s3.Bucket(this, 'MyBucket',
    {bucketName: 'fooBucket'}
    );
    fn.addEventSource(
      new S3EventSource(bucket, {
        events: [s3.EventType.OBJECT_CREATED],
      })
    );
  }
}

assuming that there is a my_dynamodb_put typescript function that put an Item in fooTable dynamodb table and a my_s3_put typescript function that put an object in the fooBucket S3 Bucket, you will get the following result:

Known limitations

Some filters can also be specified in the S3EventSource to determine which objects trigger this event. These are not supported, and this extension will create links regardless of filters.

DynamoEventSource

When the call to the addEventSource API takes an instance of aws-cdk-lib/aws-lambda-event-sources.DynamoEventSource, a property Name of dynamodb tables triggering the lambda is added to the lambda. This property saves the name of the dynamodDB Tables that would trigger the lambda. The analyzer creates a call link to the lambda function object from all callables linked to the given table.

For example, when analyzing the following source code:

import * as cdk from 'aws-cdk-lib';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { DynamoEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
import { Construct } from 'constructs';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';


export class SqsLambdaStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Lambda function
    const fn = new lambda.Function(this, 'MyLambda', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('resources/lambda')
    });
    const table = new dynamodb.Table(this, 'MyTable', {
      tableName : 'fooTable'
    });
    fn.addEventSource( new DynamoEventSource(table, {
        startingPosition: lambda.StartingPosition.LATEST,
      }));
    
  }
}

assuming that there is a my_dynamodb_put typescript function that put an Item in fooTable dynamodb table , you will get the following result:

Known limitations

  • if the lambda instance is accessed through the fromFunctionArn or the fromFunctionName API the eventSource support will not work.

Api Gateway support

Supported APIs

A basic support is provided for the following APIs:

  • aws-cdk-lib/aws-apigatewayv2.HttpApi.addRoutes
  • aws-cdk-lib/aws-apigateway.RestApi
  • aws-cdk-lib/aws-apigateway.LambdaRestApi

Detailed support for aws-cdk-lib/aws-apigateway

We support RestApi instantiated with both:

  • aws-cdk-lib/aws-apigateway.RestApi
  • aws-cdk-lib/aws-apigateway.LambdaRestApi

The RestApi instances have a root attribute that represents the root resource of the API endpoint (’/’). From this root, a path can be built using a succession of addResource method calls.

When an addMethod API call is found on a Resource, an AWS {Verb} API Gateway object is created (where {Verb} is derived from the first argument of the API call). The second argument of the addMethod API is checked:

  • if it is an instance of aws-cdk-lib/aws-apigateway.LambdaIntegration, a callLink from the API Gateway to the corresponding AWS Lambda Function is created.
  • if it is an instance of aws-cdk-lib/aws-apigateway.HttpIntegration, a TypeScript {Verb} HTTP service object is created, along with a callLink from the API Gateway to that object. The name of this object is derived from the argument passed to the HttpIntegration instantiation.
  • if it is an instance of aws-cdk-lib/aws-apigateway.AwsIntegration and if the service property is ‘sqs’ or ‘sns’ a NodeJS AWS SQS Publisher or NodeJS AWS SNS Publisher object is created, along with a callLink from the API Gateway to that object.

When no integration is provided to the addMethod API, and the RestApi was instantiated using LambdaRestApi, a callLink is created from the API Gateway to the AWS Lambda Function that was passed as the handler property to the LambdaRestApi instantiation.

Here is an example, when analyzing the following source code:

import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as sns from 'aws-cdk-lib/aws-sns';


export class LambdaLayerStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const fn = new lambda.Function(this, 'LambdaConstructID', {
        runtime: lambda.Runtime.NODEJS_LATEST,
        code: lambda.Code.fromAsset('resources/lambda'),
        handler: 'index.handler',
        functionName: 'FooFunction'    
      }
    );
    
    const topic = new sns.Topic(this, 'MyTopic', {
      topic_name: 'my_topic'}
    );

    const api = new apigateway.RestApi(this, 'myapi', {
      proxy: false
    });

    const base = api.root.addResource('base');
    const r1 = base.addResource('path');
    r1.addMethod('GET', new apigateway.LambdaIntegration(fn)); 

    const r2 = base.addResource('otherpath');
    r2.addMethod('GET', new apigateway.HttpIntegration('http://some/url')); 

    r2.addMethod('POST', new apigateway.AwsIntegration({
        service: 'sns',
        integrationHttpMethod: 'POST',
        path: `${this.account}/${topic.topicName}`,
        options: {}
      }));   

  }
}

you will get the following result:

Known limitations

  • aws-cdk-lib/aws-apigateway.AWSIntegration is supported only for sns and sqs services
  • addProxy API is not supported

Detailed support for aws-cdk-lib/aws-apigatewayv2

When the aws-cdk-lib/aws-apigatewayv2.HttpApi.addRoutes API is used in a .ts source file, an AWS {Verb} API Gateway object is created, where {Verb} is extracted from the methods property. The name of this object is derived from the path property.

If the integration property is instance of aws-cdk-lib/aws-apigatewayv2-integrations.HttpLambdaIntegration, a link is created from the API Gateway to the corresponding AWS Lambda Function.

If the integration property is an instance of aws-cdk-lib/aws-apigatewayv2-integrations.HttpUrlIntegration, a Typescript {Verb} http service object is created along with a callLink from the API Gateway to that object. The name of that object is derived from the second argument passed to the HttpUrlIntegration instantiation.

For example, when analyzing the following source code:

import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
import * as apigwv2 from 'aws-cdk-lib/aws-apigatewayv2';
import * as integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations';


export class LambdaLayerStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const fn = new lambda.Function(this, 'LambdaConstructID', {
        runtime: lambda.Runtime.NODEJS_LATEST,
        code: lambda.Code.fromAsset('resources/lambda'),
        handler: 'index.handler',
        functionName: 'FooFunction'    
      }
    );

    const api = new apigwv2.HttpApi(this, 'HttpApi');

    api.addRoutes({
      path: '/foo/path',
      methods: [apigwv2.HttpMethod.GET],
      integration: new integrations.HttpLambdaIntegration(
        'LambdaIntegration',
        fn,
      ),
    });

    api.addRoutes({
      path: '/books',
      methods: [apigwv2.HttpMethod.GET],
      integration: new integrations.HttpUrlIntegration('GetBooksIntegration', 'https://get-books-proxy.example.com'),
    });
  }
}

you will get the following result:

Detailed support for aws-cdk-lib/aws-sns-subscriptions

When an instance of aws-cdk-lib/aws-sns.Topic is found in the analyzed source code, and that instance invokes the addSubscription API at least once with a supported subscription type as its argument, a NodeJS AWS SNS Subscriber object is created.

The name of the NodeJS AWS SNS Subscriber object is derived from the name of the SNS Topic.

For each supported subscription passed to addSubscription, a corresponding object is created, and a callLink is established from the NodeJS AWS SNS Subscriber to that object.

The table below lists the supported subscription types and the corresponding objects that the extension creates:

Supported subscription Object created
aws-cdk-lib/aws-sns-subscriptions.LambdaSubscription NodeJS Call to AWS Lambda Function
aws-cdk-lib/aws-sns-subscriptions.UrlSubscription TypeScript Post http service
aws-cdk-lib/aws-sns-subscriptions.SqsSubscription NodeJS AWS SQS Publisher
aws-cdk-lib/aws-sns-subscriptions.EmailSubscription NodeJS Email
aws-cdk-lib/aws-sns-subscriptions.SmsSubscription NodeJS SMS

For example, when analyzing the following source code:

import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as subscriptions from 'aws-cdk-lib/aws-sns-subscriptions';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as sqs from 'aws-cdk-lib/aws-sqs';

export class SnsLambdaStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // SNS topic
    const topic = new sns.Topic(this, 'Topic', {
      topicName:'FooTopic'
    });

    // Lambda function
    const fn = new lambda.Function(this, 'Handler', {
      functionName: 'FooFunction',
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromInline(`
        exports.handler = async (event) => {
          console.log(JSON.stringify(event, null, 2));
        };
      `),
    });

    // Subscribe Lambda to SNS
    topic.addSubscription(
      new subscriptions.LambdaSubscription(fn)
    );
    
    // SQS Queue
    const queue = new sqs.Queue(this, 'MyQueue', {
      queueName: 'FooQueue'
    });

    // HTTPS subscription
    topic.addSubscription(
      new subscriptions.UrlSubscription(
        'https://example.com/webhook'
      )
    );

    // SQS subscription
    topic.addSubscription(
      new subscriptions.SqsSubscription(queue)
    );

    // Email subscription
    topic.addSubscription(
      new subscriptions.EmailSubscription(
        'user@example.com'
      )
    );

    // SMS subscription
    topic.addSubscription(
      new subscriptions.SmsSubscription(
        somephonenumber
      )
    );
  }
}

you will get the following result:

Support for aws-cdk-lib/aws-s3.Bucket.addEventNotification

When a call to the aws-cdk-lib/aws-s3.Bucket.addEventNotification API is detected, the first argument of the call (the event type) and the destination object are analyzed.

Support is provided only when the destination argument is an instance of one of the following types:

  • aws-cdk-lib/aws-s3-notifications.LambdaDestination
  • aws-cdk-lib/aws-s3-notifications.SqsDestination
  • aws-cdk-lib/aws-s3-notifications.SnsDestination

For supported destinations, the corresponding S3 Event Handler is inferred and linked as described below.

support for aws-cdk-lib/aws-s3-notifications.LambdaDestination

When the addEventNotification API is called with an instance of aws-cdk-lib/aws-s3-notifications.LambdaDestination, the corresponding AWS Lambda Function object is inferred from the first argument of the destination instantiation.

This AWS Lambda Function object is considered the S3 Event Handler.

The property CAST_AWS_S3_Event_Handler.s3_events is stored on that object and contains:

  • the bucket name
  • the S3 event type that triggers the handler

support for aws-cdk-lib/aws-s3-notifications.SqsDestination

When the addEventNotification API is called with an instance of aws-cdk-lib/aws-s3-notifications.SqsDestination, the queue name is inferred from the first argument of the destination instantiation.

If the queue name is successfully inferred, a NodeJS AWS SQS Publisher object is created.

Otherwise, a NodeJS AWS Unknown SQS Publisher object is created.

The created object is considered the S3 Event Handler.

The property CAST_AWS_S3_Event_Handler.s3_events is stored on that object and contains:

  • the bucket name
  • the S3 event type that triggers the handler

The com.castsoftware.wbslinker extension then creates a callLink to this S3 Event Handler based on the stored s3_events property.

support for aws-cdk-lib/aws-s3-notifications.SqsDestination

When the addEventNotification API is called with an instance of aws-cdk-lib/aws-s3-notifications.SnsDestination, the topic name is inferred from the first argument of the destination instantiation.

If the topic name is successfully inferred, a NodeJS AWS SNS Publisher object is created.

Otherwise, a NodeJS AWS Unknown SNS Publisher object is created.

The created object is considered the S3 Event Handler.

The property CAST_AWS_S3_Event_Handler.s3_events is stored on that object and contains:

  • the bucket name
  • the S3 event type that triggers the handler

The com.castsoftware.wbslinker extension then creates a callLink to this S3 Event Handler based on the stored s3_events property.

Based on the bucket name and event type provided in CAST_AWS_S3_Event_Handler.s3_events, the com.castsoftware.wbslinker extension creates a call link to the S3 Event Handler object.

The link is created from all callables already linked to the given bucket through a matching link type, as defined in the table below (* matches any string):

event type matching link types
OBJECT_CREATED useInsert, useUpdate
OBJECT_CREATED_* useInsert, useUpdate
OBJECT_REMOVED useDelete
OBJECT_REMOVED_* useDelete
other event types None

Filters (such as prefix or suffix) can be specified in the addEventNotification call to restrict which objects trigger the event. These filters are not currently supported, and links are created regardless of filters.

Example

When analyzing the following source code:

import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as sqs from 'aws-cdk-lib/aws-sqs';
import * as s3n from 'aws-cdk-lib/aws-s3-notifications';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as lambda from 'aws-cdk-lib/aws-lambda';

export class SimpleStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const bucket = new s3.Bucket(this, 'MyBucket',
        {bucketName: 'fooBucket'});

    const queue = new sqs.Queue(this, 'MyQueue',
         { queueName: 'fooQueue'
    });

    const topic = new sns.Topic(this, 'MyTopic',
      {topicName: 'fooTopic'}    
    );

    const fn = new lambda.Function(this, 'MyFunction', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      functionName: 'MyFunction',
      code: lambda.Code.fromInline(
        'exports.handler = async (event) => { console.log(JSON.stringify(event)); };'
      ),
    });

    bucket.addEventNotification(
      s3.EventType.OBJECT_CREATED,
      new s3n.LambdaDestination(fn)
    );

    bucket.addEventNotification(
      s3.EventType.OBJECT_DELETED,
      new s3n.SqsDestination(queue)
    );
    
    bucket.addEventNotification(
      s3.EventType.OBJECT_CREATED,
      new s3n.SnsDestination(topic)
    );

    bucket.addEventNotification(
      s3.EventType.OBJECT_DELETED,
      new s3n.SnsDestination(topic)
    );      
  }
}

you will get the following result:

Known limitations

  • if the lambda instance is accessed through the fromFunctionArn or the fromFunctionName API the LambdaDestination support will not work.