How to capture Table changes with DynamoDB Streams & Lambda with AWS CDK

Dynamo DB stream - Definition

What is a stream ?

According to the AWS Documentation :

A DynamoDB stream is an ordered flow of information about changes to items in a DynamoDB table. Whenever an application creates, updates, or deletes items in the table, DynamoDB Streams writes a stream record with the primary key attributes of the items that were modified

Use case

According to the definition, every time a change happens in a DynamoDB table, it is stored in a stream.

Okay, but what can we do with that stream ?

Well, you can use a stream to invoke a Lambda function.

untitled@2x (6).png

For example, you have an application that creates new Users on a DynamoDB table.

It could be useful to send to automatically an email to your new users.

You can do that with DynamoDB streams.

Let's do this

Let's create the main folder of the project

mkdir streamLambdaExample
cd streamLambdaExample
npm init -y

Then install CDK and aws-lambda package

npm install -g aws-cdk
npm i @aws-cdk/aws-lambda
npm i @aws-cdk/aws-dynamodb
npm i @aws-cdk/aws-lambda-event-sources
mkdir cdk-folder
cdk init app --language typescript

#### CDK part

Open the file lib/cdk-folder-stack.ts

import * as cdk from '@aws-cdk/core';
import * as dynamodb from '@aws-cdk/aws-dynamodb';
import * as lambda from '@aws-cdk/aws-lambda';
import * as path from 'path';
import { DynamoEventSource } from '@aws-cdk/aws-lambda-event-sources';

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

    const usersTable = new dynamodb.Table(this, 'Users', {
      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
      stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
      tableName: 'Users',
    });

    const myLambdaFunction = new lambda.Function(this, 'my-lambda', {
      runtime: lambda.Runtime.NODEJS_14_X,
      memorySize: 256,
      timeout: cdk.Duration.seconds(60),
      handler: 'index.main',
      code: lambda.Code.fromAsset(path.join(__dirname, '/../app/my-lambda/')),
    });

    myLambdaFunction.addEventSource(new DynamoEventSource(usersTable, {
      startingPosition: lambda.StartingPosition.LATEST,
    }));
  }
}

Lambda part

Now the lambda code

mkdir app
cd app
mkdir my-lambda
cd my-lambda
npm init -y 
touch index.js

We are just going to log the DynamoDB record.

exports.main = async (event) => {
    for (const record of event.Records){
        console.log('DynamoDB Record: %j', record.dynamodb);
    }
};

Let's try it

Let's bootstrap first

cdk bootstrap
⏳  Bootstrapping environment aws://XXXXXXXXXXXXX/us-east-1...
 ✅  Environment aws://XXXXXXXXXXXXXX/us-east-1 bootstrapped (no changes).

Second command, to create the Cloudformation template for our app :

cdk synth

And now, let's deploy !

cdk deploy

On the console

First, let's see our DynamoDB table

Go to DynamoDB on the console (on the right region), to see your Users table :

Capture d’écran 2021-12-13 à 19.26.58.png

We are going to create a User on the table (click on Create Item)

Capture d’écran 2021-12-13 à 19.27.21.png

Fill with the info you want :

Capture d’écran 2021-12-13 à 19.27.46.png

Hit save.

If we configured everything correctly, our lambda should be triggered and display the log.

Go to the Lambda console (you can see that the trigger is DynamoDB) :

Capture d’écran 2021-12-13 à 19.28.15.png

Go to the Cloudwatch Logs of your Lambda :

Capture d’écran 2021-12-13 à 19.48.06.png

Your lambda has been triggered by the DynamoDB stream ! Well done !

Cleaning

Don't forget to clean after this tutorial, i don't want you to have a huge bill on AWS!

cdk destroy

Conclusion

Fell free to ask me questions in the comments ! See you in the next one ! 🤖

Did you find this article valuable?

Support Sonia Manoubi by becoming a sponsor. Any amount is appreciated!