how.wtf

Applying event filters to AWS Lambda Functions with the AWS CDK

· Thomas Taylor

The primary motive for writing this article is to address the common error I repeatedly received while troubleshooting event filters:

Invalid filter pattern definition. (Service: AWSLambda; Status Code: 400; Error Code: InvalidParameterValueException

For my case, the goal was to invoke an AWS Lambda function via a DynamoDB stream.

What are Lambda Event Filters

Lambda event filters allow developers to specify which types of records from a stream or queue are submitted to a Lambda. Event filters are included in event source mapping definitions so that Lambda functions are only invoked when the filter criteria is met.

DynamoDB TTL deletion event filter

My use case involved invoking a lambda function to archive resources when a DynamoDB TTL expiry was met. Fortunately, the DynamoDB documentation has a section that describes how to achieve this.

The required filter criteria is as follows:

 1{
 2  "Filters": [
 3    {
 4      "Pattern": {
 5        "userIdentity": {
 6          "type": ["Service"],
 7          "principalId": ["dynamodb.amazonaws.com"]
 8        }
 9      }
10    }
11  ]
12}

This filter patterns suggests that only actions submitted by the service principal dynamodb.amazonaws.com should be processed by the receiving consumer. This makes sense because the DynamoDB service deletes expired TTL items on our behalf.

Adding event filters to Lambda Functions with AWS CDK

The following example demonstrates how to add event filters to a Lambda function using the AWS CDK in TypeScript:

 1import * as path from 'path';
 2
 3import { 
 4  Code, 
 5  FilterCriteria,
 6  Function,
 7  Runtime,
 8  StartingPosition
 9} from 'aws-cdk-lib/aws-lambda';
10
11import { AttributeType, StreamViewType, Table } from 'aws-cdk-lib/aws-dynamodb';
12
13import { DynamoEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
14
15const table = new Table(this, 'Table', {
16  partitionKey: {
17    name: 'id',
18    type: AttributeType.STRING
19  },
20  stream: StreamViewType.NEW_IMAGE
21});
22
23const lambda = new Function(this, 'Function', {
24  runtime: Runtime.NODEJS_20_X,
25  handler: 'index.handler',
26  code: Code.fromAsset(path.join(__dirname, 'lambda-handler'))
27});
28
29lambda.addEventSource(
30  new DynamoEventSource(databaseTable, {
31    startingPosition: StartingPosition.TRIM_HORIZON,
32    filters: [
33      FilterCriteria.filter({
34        userIdentity: {
35          type: ['Service'],
36          principalId: ['dynamodb.amazonaws.com']
37        }
38      })
39    ]
40  })
41)

The crucial part is the inner filters attribute within the event source definition:

 1lambda.addEventSource(
 2  new DynamoEventSource(databaseTable, {
 3    startingPosition: StartingPosition.TRIM_HORIZON,
 4    filters: [
 5      FilterCriteria.filter({
 6        userIdentity: {
 7          type: ['Service'],
 8          principalId: ['dynamodb.amazonaws.com']
 9        }
10      })
11    ]
12  })
13)

It’s important to note that the static method of FilterCriteria.filter adds the pattern top-level attribute and marshals the inner JSON on our behalf.

As of April 2024, the filters attribute is available on many supported event sources:

#typescript   #aws   #aws-cdk   #serverless  

Reply to this post by email ↪