Building Serverless Applications with AWS CDK
AWS CDK simplifies serverless infrastructure. After building production serverless apps, here’s how to use CDK effectively.
CDK Basics
Installation
npm install -g aws-cdk
cdk --version
# Initialize project
cdk init app --language typescript
Basic Stack
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
export class ServerlessStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Lambda function
const helloFunction = new lambda.Function(this, 'HelloFunction', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
});
// API Gateway
new apigateway.LambdaRestApi(this, 'HelloApi', {
handler: helloFunction,
});
}
}
Lambda Functions
Basic Function
const myFunction = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda/my-function'),
timeout: cdk.Duration.seconds(30),
memorySize: 256,
environment: {
TABLE_NAME: table.tableName,
},
});
Function with Layers
const layer = new lambda.LayerVersion(this, 'MyLayer', {
code: lambda.Code.fromAsset('layer'),
compatibleRuntimes: [lambda.Runtime.NODEJS_18_X],
});
const function = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
layers: [layer],
});
API Gateway
REST API
const api = new apigateway.RestApi(this, 'MyApi', {
restApiName: 'My API',
description: 'My serverless API',
});
const helloResource = api.root.addResource('hello');
helloResource.addMethod('GET', new apigateway.LambdaIntegration(helloFunction));
HTTP API
import * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2';
const httpApi = new apigatewayv2.HttpApi(this, 'MyHttpApi');
httpApi.addRoutes({
path: '/hello',
methods: [apigatewayv2.HttpMethod.GET],
integration: new apigatewayv2.HttpLambdaIntegration(
'HelloIntegration',
helloFunction
),
});
DynamoDB
Table Definition
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
const table = new dynamodb.Table(this, 'MyTable', {
partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
// Grant permissions
table.grantReadWriteData(myFunction);
S3
Bucket and Lambda Trigger
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3n from 'aws-cdk-lib/aws-s3-notifications';
const bucket = new s3.Bucket(this, 'MyBucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
const processorFunction = new lambda.Function(this, 'Processor', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda/processor'),
});
bucket.addEventNotification(
s3.EventType.OBJECT_CREATED,
new s3n.LambdaDestination(processorFunction)
);
EventBridge
Event Rule
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';
const rule = new events.Rule(this, 'ScheduleRule', {
schedule: events.Schedule.rate(cdk.Duration.hours(1)),
});
rule.addTarget(new targets.LambdaFunction(myFunction));
Best Practices
- Use constructs - Reusable components
- Environment variables - Configuration
- IAM permissions - Least privilege
- Error handling - Dead letter queues
- Monitoring - CloudWatch alarms
- Testing - Unit and integration tests
- Documentation - Clear comments
- Versioning - Semantic versioning
Conclusion
AWS CDK enables:
- Type-safe infrastructure
- Reusable constructs
- Better DX
- Infrastructure as code
Start with simple stacks, then build reusable constructs. The patterns shown here create production serverless applications.
Building serverless applications with AWS CDK from September 2021, covering Lambda, API Gateway, and DynamoDB.