Modernizing Serverless Workflows Adopting AWS CDK: A Journey from Serverless Framework.

Gabriel Torres
Towards AWS
Published in
6 min readOct 16, 2023

--

Over the past few years, my tenure at my current company has presented a substantial challenge. The primary focus has been on transitioning our application, originally built using the Serverless Framework, to AWS CDK. This transition reflects the changing landscape of team dynamics and approaches over this period.

This shift encompasses not just the application itself but also encompasses the entire application lifecycle and its associated intricacies. However, the scope of this article will be concentrated solely on the application aspect of the migration journey — specifically, how to migrate a serverless and cloud-native application from the Serverless Framework to AWS CDK.

To facilitate this, we will outline a fundamental event-driven architecture to establish a clear and structured foundation for the migration process.

Cloud-Native Components:

API Gateway (Apigateway):

  • Description: Amazon API Gateway is a fully managed service provided by AWS that allows you to create, publish, and manage APIs for your applications. It serves as a front-end for your backend services, enabling you to expose RESTful or WebSocket APIs to clients such as web and mobile applications.
  • Use Cases: API Gateway is commonly used to build and deploy RESTful APIs or WebSocket APIs, enabling secure and controlled access to your application’s functionality. It can also handle authentication, authorization, request/response transformation, and can integrate with various AWS services or custom backend applications.

Lambda Function:

  • Description: AWS Lambda is a serverless compute service that allows you to run code in response to events without the need to manage servers. You can upload your code, specify the event source (e.g., API Gateway, S3, SQS, etc.), and Lambda automatically scales and manages the compute resources needed to execute your code.
  • Use Cases: Lambda functions are used for a wide range of tasks, including data processing, real-time file handling, backend logic for web applications, and more. They are particularly useful for building serverless applications, event-driven systems, and microservices.

SQS Standard (Amazon Simple Queue Service):

  • Description: Amazon SQS is a managed message queue service that allows you to decouple the components of a cloud application. SQS provides a reliable and scalable way to transmit any volume of data between distributed systems, microservices, and serverless applications.
  • Use Cases: SQS is commonly used in distributed systems to enable asynchronous communication between components. It ensures that messages are reliably delivered and processed, even when systems experience varying levels of load. SQS is suitable for scenarios such as task queues, event-driven architectures, and decoupling services.

DynamoDB:

  • Description: Amazon DynamoDB is a managed NoSQL database service provided by AWS. It is designed to provide low-latency and seamless scalability for applications that require high-performance, highly available, and fully managed NoSQL databases.
  • Use Cases: DynamoDB is used for a variety of applications, including web and mobile applications, gaming, IoT, and more. It excels in scenarios where fast read/write access to data is essential and can be configured for both eventual consistency and strong consistency. DynamoDB tables are automatically replicated across multiple availability zones for high availability.

Let’s do it: writing serverless applications via Serverless Framework.

First, we defined the serverless application using Serverless Framework like an IAC and then converted it to CDK.

Step 1: Prerequisites

  • Ensure you have Node.js and npm installed on your development machine.
  • Install the Serverless Framework globally: npm install -g serverless
  • Set up your AWS credentials by configuring AWS CLI or using environment variables.

Step 2: Initialize a Serverless Framework Project

Open your terminal and navigate to your project directory:

mkdir my-serverless-app
cd my-serverless-app

Initialize a new Serverless Framework project:

serverless create --template aws-nodejs-typescript --path my-service
cd my-service

This will create a new Serverless service with a TypeScript template.

Step 3: Define Your Serverless Service Configuration

Edit the serverless.yml file to define your service configuration. Here's a basic example:

service: my-service
provider:
name: aws
runtime: nodejs14.x
region: us-east-1
functions:
myFunction:
handler: handler.myFunction
events:
- http:
path: myEndpoint
method: GET
resources:
Resources:
MyDynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: myTable
AttributeDefinitions:
- AttributeName: id
AttributeType: N
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5

This configuration defines a Lambda function (myFunction) that's exposed via an HTTP endpoint and a DynamoDB table (MyDynamoDBTable).

Step 4: Implement the Lambda Function

Create a TypeScript file for your Lambda function in the src directory. For example, create src/handler.ts and define your Lambda function there:

import { APIGatewayProxyHandler } from 'aws-lambda';

export const myFunction: APIGatewayProxyHandler = async (event, context) => {
// Your Lambda function logic here
return {
statusCode: 200,
body: JSON.stringify({ message: 'Hello from Lambda!' }),
};
};

Step 5: Implement SQS and DynamoDB Logic

To work with SQS and DynamoDB, you can use the AWS SDK for JavaScript in your TypeScript code. For example, to send a message to an SQS queue or interact with DynamoDB, you’ll need to import and use the appropriate AWS SDK functions.

Step 6: Deploy Your Serverless Application

Deploy your serverless application using the Serverless Framework:

serverless deploy

This command packages your code and deploys it to AWS. It will create the Lambda function, API Gateway, DynamoDB table, and any other AWS resources defined in your serverless.yml configuration.

Well done, the serverless application is running via serverless framework. This application is based on a cloud-native application, such as the recommendation of AWS.

We are ready to become this application running via serverless framework to CDK.

Let’s do it: writing serverless applications via CDK

Certainly, let’s convert your service configuration into a CDK (Amazon Cloud Development Kit) application step by step in English:

Step 1: Initialize a CDK project.

cdk init app - language=typescript

Step 2: Install the required dependencies.

npm install @aws-cdk/aws-lambda @aws-cdk/aws-apigateway @aws-cdk/aws-dynamodb

Step 3: Create a new TypeScript file that represents your infrastructure. Name it, for example, `my-service-stack.ts`.

Step 4: In the TypeScript file, import the necessary libraries and define your infrastructure. Here’s an example of what it could look like:

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';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';

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

// Define the DynamoDB table
const myDynamoDBTable = new dynamodb.Table(this, 'MyDynamoDBTable', {
tableName: 'myTable',
partitionKey: {
name: 'id',
type: dynamodb.AttributeType.NUMBER,
},
readCapacity: 5,
writeCapacity: 5,
});

// Define the Lambda function
const myFunction = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'handler.myFunction',
});

// Grant the Lambda function read/write access to the DynamoDB table
myDynamoDBTable.grantReadWriteData(myFunction);

// Define the API Gateway
const api = new apigateway.RestApi(this, 'MyApi', {
deployOptions: {
stageName: 'prod',
},
});

// Create an API Gateway endpoint that invokes the Lambda function
const myEndpoint = api.root.addResource('myEndpoint');
const integration = new apigateway.LambdaIntegration(myFunction);
myEndpoint.addMethod('GET', integration);
}
}

const app = new cdk.App();
new MyServiceStack(app, 'MyServiceStack');

Step 5: Deploy your CDK application.

cdk deploy

Conclusion

In conclusion, migrating from the Serverless Framework to AWS CDK is a strategic move that offers enhanced control, flexibility, and integration with AWS services. While it may require an initial learning curve, the efficiency, scalability, and long-term maintainability benefits make it a compelling choice for modern serverless infrastructure development.

Let me know if you want to know more about it or my last project using CDK.

--

--