Applying event filters to AWS Lambda Functions with the AWS CDK
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:
- The
DynamoEventSource
documentation definition - The
KafkaEventSource
documentation definition - The
KinesisEventSource
documentation definition - The
ManagedKafkaEventSource
documentation definition - The
S3EventSource
documentation definition - The
SelfManagedKafkaEventSourceProps
documentation definition - The
SqsEventSourceProps
documentation definition