Mastering AWS CDK Part 1: Using Built-In Constructs for Serverless APIs

Mastering AWS CDK Part 1: Using Built-In Constructs for Serverless APIs

This article was written by Iggy Yuson. Iggy, a DevOps engineer based in the Philippines, specializes in cloud-native applications on AWS. He has a broad skill set in creating comprehensive solutions for web and mobile platforms and excels in deploying serverless architectures within AWS.

In the domain of Infrastructure as Code (IaC) on AWS, CloudFormation is prominently positioned as the core service. Numerous other IaC platforms, such as the Serverless Framework, AWS SAM, and even Terraform, ultimately leverage CloudFormation for deployment. Moreover, the AWS Cloud Development Kit (CDK) has emerged as a notable contender in this field.

AWS CDK distinguishes itself by embracing widely-used programming languages. Instead of depending on YAML or proprietary syntax, developers can use languages such as Python, JavaScript, TypeScript, Java, C#, and Go to define infrastructure with AWS CDK. This familiarity speeds up the learning process, allowing developers to focus on creating business solutions instead of dealing with intricate infrastructure details.

In contemporary backend development, creating RESTful APIs has become an essential responsibility. What used to require complex setups and deployments can now be simplified through the adoption of serverless architectures.

Below is the framework for constructing serverless RESTful APIs utilizing the AWS CDK:

This structure represents a traditional three-tiered layout. The AWS API Gateway leads the way and acts as the interface for front-end engagements. AWS Lambda delivers serverless computing power, guaranteeing scalability and streamlined processing. Concurrently, Amazon DynamoDB serves as the foundation, delivering dependable storage and data persistence.

Prerequisites

  1. Set up a development environment or account within AWS.
  2. Install Node, AWS CDK, and the AWS CLI.
  3. Configure AWS credentials locally.

Initializing a new AWS CDK App

Next, to start a new project with AWS CDK, enter the following command:

Utilizing npx guarantees the usage of the most recent version of AWS CDK.

For this architecture with AWS CDK, TypeScript is selected as the programming language. If TypeScript isn't installed on the system, you can add it using this command:

Bootstrapping

Bootstrapping marks a crucial starting point in utilizing AWS CDK, empowering it with the requisite permissions to function within your account.This essential step needs to be accomplished prior to deploying any AWS CDK applications. Throughout the bootstrapping process, necessary resources are allocated, such as storage for vital files and IAM roles to streamline deployments. This process culminates in the establishment of a CloudFormation Stack, commonly referred to as CDKToolKit.

To start the bootstrapping process for your application, execute the following command:

In AWS CDK, constructs act as the building blocks of infrastructure, much like Lego bricks in a construction kit. Each construct represents a logical resource in CloudFormation, which subsequently materializes into actual resources within the cloud environment. These constructs reside within Stacks in AWS CDK, reflecting the notion of CloudFormation Stacks. Essentially, an AWS CDK application outlines one or more of these stacks.

The procedure for setting up an application and stack can be seen in bin/tutorials-dojo-cdk-app.ts. When this application is deployed to the cloud, it will create a CloudFormation stack called TutorialsDojoCdkAppStack.

As mentioned earlier, constructs reside within AWS CDK Stacks. AWS provides a collection of pre-configured constructs, enabling developers and DevOps professionals to efficiently create Infrastructure as Code. An example Stack is located in lib/tutorials-dojo-cdk-app-stack.ts, which AWS generates during the initialization of an AWS CDK application. To enhance user support, AWS suggests using an SQS construct as a reference for defining other constructs. The implementation of the serverless RESTful API will be incorporated within this file.

The DynamoDB Table AWS CDK Construct

First, extract the DynamoDB construct from the aws-cdk-lib NodeJS package and integrate it into the lib/tutorials-dojo-cdk-app-stack.ts Stack. This aws-cdk-lib package was installed during the initialization of the AWS CDK application.

In the Stack class, create an instance of the DynamoDB table. The provided snippet demonstrates the AWS CDK approach to building a DynamoDB table, defining fundamental attributes such as partitionKey and tableName. It's important to note that these attributes cover only a portion of the capabilities offered by the DynamoDB Table Construct. When exploring new constructs, referring to the official AWS documentation is advisable to fully leverage their functionalities.

The Lambda Function AWS CDK Construct

Start by importing the Lambda construct from the aws-cdk-lib NodeJS package and adding it to the Stack.

Afterwards, set up the Lambda function inside the Stack class. The example provided emphasizes key properties necessary for configuring this Lambda function, including the mandatory properties such as runtime, handler, and code.

The runtime is designated to define the programming language and version in which the Lambda function will operate. It's worth noting that a Lambda function can run in Python even if the AWS CDK construct used to declare it is written in TypeScript, and the same applies to other programming languages.

The handler convention follows the format <file-name>.<function-name>. Here, file-name represents the name of the file containing the Lambda function code, while function-name specifies the particular method or function that Lambda should execute upon invocation. In this scenario, the Lambda function is located in the index.ts file, and the main method to be invoked is named handler. This clarifies why the handler is referred to as index.handler.

The code property specifies the location of the Lambda function within the codebase. This feature is notable in Infrastructure as Code (IaC) tools like AWS CDK, as CloudFormation does not offer this direct capability. Typically, CloudFormation requires Lambda code to be uploaded to Amazon S3 first, followed by referencing the bucket and key in the CloudFormation script. In contrast, in this scenario, the Lambda function code is located in the lambda directory at the project's root.

Lastly, the environment property within the Lambda function construct enables the definition of the Lambda function’s environment variables, though it's optional. In this scenario, the DynamoDB table name is provided as an environment variable. This simplifies its utilization during the Lambda function's execution, particularly when interacting with the AWS SDK to perform operations on the specified DynamoDB table.

The Lambda function construct's official AWS documentation provides an extensive list of properties beyond what is demonstrated in this example. It's crucial for users, particularly those aiming to enhance their Lambda functions using AWS CDK as their chosen Infrastructure as Code (IaC) tool, to familiarize themselves with these supplementary configuration choices. These insights offer opportunities for more refined adjustments and personalization of Lambda functions.

To adhere to the defined Lambda function construct, it's crucial to make adjustments to the current file structure of the AWS CDK project. Here's the required course of action:

  • Establish a new directory titled lambda at the root level of the project.
  • Within the lambda directory, generate a file named index.ts.

Here's how the revised file structure appears:

Finally, paste the provided code into the newly generated index.ts file.

Grant the Lambda Function Read and Write Access to the DynamoDB Table

To grant the Lambda function with read and write permissions for the DynamoDB table, take into account the constructs dynamoTable and lambdaFunction. In this context, dynamoTable corresponds to the previously defined DynamoDB table, while lambdaFunction refers to the newly established Lambda function.

This situation highlights the simplicity of AWS CDK's abstraction. Typically, enabling a Lambda function to access a DynamoDB table requires a complex process: establishing an execution role and specifying permissions in a lengthy JSON format, often spanning multiple lines of code, particularly with CloudFormation. However, AWS CDK streamlines this elaborate setup. Through its abstraction features, what used to be a lengthy configuration can now be condensed into a concise, single line of code. This not only simplifies the process but also improves the developer's workflow.

The Lambda Layer AWS CDK Construct

Lambda layers provide a unique feature within AWS Lambda, enabling the sharing of code and various assets across multiple Lambda functions. This not only promotes code reuse but also improves the efficiency of Lambda cold starts. Moving repetitive code to layers reduces the size of customers' Lambda deployment packages.

Within this project's scope, it's expected that the aws-sdk package will be essential across numerous Lambda functions as they grow. Continuously generating separate package.json files and installing the same dependencies for each Lambda function is inefficient and goes against AWS recommendations. Therefore, the most effective approach is to utilize Lambda layers to handle shared code and packages used repeatedly across Lambda functions.

With our existing Stack, here's how you can create a Lambda Layer:

It's essential to verify that the compatibleRuntimes property of the Lambda layer aligns with that of the intended Lambda function. Incompatibilities in runtime versions can result in deployment errors within CloudFormation. Similar to its role in the Lambda function structure, the code property specifies the layer's location in the codebase. Although the description property is optional in the Lambda layer construct, it provides a means to annotate the layer, aiding its identification in the AWS Console.

After setting up the Lambda layer, the next step is to link it with the intended Lambda function. Without this connection, the function will be unaware of the layer's existence.

For a thorough understanding and potential customization, it's advisable to refer to the official AWS documentation pertaining to the Lambda layer construct.

To smoothly integrate with the Lambda layer structure, modifications to the codebase's file organization are necessary. Here are the steps to ensure the effective utilization of the Lambda layer:

  • Create a new directory called "layers" at the root level of the project.
  • Inside the layers directory, create a sub-directory named nodejs. This corresponds to the requirements for creating a Lambda layer intended for a Node.js runtime. For more in-depth information, refer to the official AWS Lambda layers documentation listed in this guide's references.
  • Go to the nodejs directory and start a new Node project using the npm init -y command. It's important to verify that the local Node version matches the specified compatibleRuntimes in the Lambda layer construct to ensure smooth deployments.
  • In the nodejs directory, install the aws-sdk package using the npm install aws-sdk command.

Here's how the updated file structure appears:

The API Gateway REST API AWS CDK Construct

The API Gateway acts as the public gateway to the backend infrastructure. Once deployed, it creates a URL that allows applications and API clients to interact with it. In this project, AWS's REST API structure is used to create a publicly accessible REST API in the AWS cloud.

One notable aspect of AWS API Gateway is its strong authorization features, which are just one part of its extensive functionality. These features ensure that only authenticated and authorized users can invoke APIs within the AWS API Gateway. For a more detailed understanding of these capabilities, refer to the official AWS API Gateway documentation. While building an API Gateway from scratch offers precise control and flexibility, it requires considerable effort. Although manual creation provides users with adaptability, it may also lead to overlooking certain AWS API Gateway features and integrations that are inherent to other AWS services.

Here's how to create an API Gateway REST API using the AWS CDK Construct:

The API Gateway REST API construct offers numerous properties. You can find a detailed list of these properties in the official AWS API Gateway REST API construct documentation. These configurations allow users to finely customize their API Gateway, including aspects such as CORS settings, headers, permitted methods, and more. In this instance, only the restApiName and description properties are utilized.

Integration of the Lambda Function to the API Gateway

The integration of Lambda functions with API Gateway has become a prominent serverless pattern in AWS. Acknowledging this trend, AWS introduced a dedicated construct for this purpose. In this scenario, the LambdaIntegration construct enables the effortless integration of a Lambda function with an API Gateway.

Moreover, AWS CDK is capable of defining and handling both resources and their corresponding methods. The below example shows how? to link a particular resource and its related methods to a Lambda function:

In this instance, the apiGateway variable represents the API Gateway REST API construct that was created earlier. These instructions connect the GET and POST methods to the API Gateway's root resource, which corresponds to the default path in the API Gateway, identified by the / path.

Furthermore, the previously defined LambdaIntegration construct is referenced here, specifying which Lambda function will process these requests once they are deployed to the cloud.

Deployment of the CDK Application

Once all these constructs are created within the lib/tutorials-dojo-cdk-app-stack.ts Stack, the file should appear similar to this:

Upon reviewing the architecture again, it becomes clear that the DynamoDB table, situated on the rightmost side in this case, was defined first. This strategy follows a widely accepted best practice in AWS CDK and similar Infrastructure as Code (IaC) tools: start with the service that has fewer integrations. Usually, this service corresponds to the resource located farthest in the architectural diagram.

To deploy the AWS CDK Stack named TutorialsDojoCdkAppStack, execute the following command in the root directory:

The tsc command compiles all TypeScript code within the project, adhering to the configurations specified in tsconfig.json, and converting it into JavaScript. This step is crucial because Lambda inherently interprets JavaScript and does not offer built-in support for TypeScript.

Additionally, when you run cdk deploy, it triggers the deployment of the TutorialsDojoCdkAppStack. You can track the progress of the deployment either in the terminal or directly within CloudFormation. If there are any deployment failures, it's advisable to review the process in CloudFormation to better understand the encountered issues.

Testing the Serverless REST API

Assessing the functionality of the REST API can be done using any API client. For this demonstration, Postman has been selected as the tool to explore the newly deployed REST API endpoints.

Prerequisites

  1. Ensure Postman is installed.
  2. Set up the REST API’s base URL as an environment variable within Postman. Upon the Stack's deployment, this URL is displayed in the terminal.
  3. Create a Postman Collection.

Testing

In the curated Postman Collection, create a new request. The first test focuses on the POST request, with the settings shown in the following image:

After clicking "Send," anticipate receiving a response that resembles the format depicted above.

The next test centers on the GET request. Duplicate the original POST request, change the method to GET, and for the body, choose "none" as GET requests typically do not include a body.

You can view the corresponding configuration below:

Upon clicking "Send," expect to receive a response that reflects the format demonstrated above.

It's important to note that as additional entries are added using the PUT Item API, they will be listed in the output of the GET Items API.

The Most Common Pitfall: Should I Still Learn CloudFormation?

In the midst of the proliferation of popular Infrastructure as Code (IaC) tools, a pertinent question emerges: Is it still relevant to master CloudFormation for deploying AWS infrastructure using IaC? The answer is a resounding yes. There's a common misconception that compares CloudFormation to assembly language and other tools like AWS CDK, Terraform, and Serverless Framework to high-level languages. However, this analogy is overly simplistic. It's important to understand that there isn't a separate AWS CDK or Terraform service within AWS. At its essence, CloudFormation serves as the foundational service, with other IaC tools offering various levels of abstraction. Ultimately, all roads lead back to CloudFormation. Understanding the fundamental principles and mechanics of CloudFormation is crucial for anyone utilizing IaC tools for deploying AWS infrastructure. Neglecting this groundwork can result in pitfalls and misconceptions during the deployment process.

Final Remarks

AWS CDK, along with other Infrastructure as Code (IaC) tools, presents a multitude of advantages that redefine modern infrastructure management. The term "Infrastructure as Code" now seems somewhat antiquated. A more fitting expression in today's landscape might be "Infrastructure IS Code." Present-day infrastructure isn't simply described or managed using code; it essentially materializes as code. Every component, spanning from networking elements to databases, is defined, configured, and monitored through coding methodologies. Relying on manual deployment, especially in production environments, has become an outdated approach for cloud-native applications. Contemporary standards lean towards IaC tools. From automation capabilities and ensured consistency to seamless CI/CD integration, the benefits of IaC are diverse, greatly benefiting both developers and DevOps professionals.

Building infrastructure in AWS using the AWS CDK enhances users' development experience by leveraging widely used programming languages. It's similar to utilizing CloudFormation but with the familiarity and flexibility of a preferred programming language. This methodology offers elevated, relevant abstractions that enhance the overall development process.

What to Expect in Part 2?

In Part 2, we further explore the concept of abstraction within the AWS CDK. This segment introduces various types of constructs within the AWS CDK, highlighting the importance of creating custom and reusable constructs. By embracing this methodology, the aim is to uphold the DRY (Don’t Repeat Yourself) principle and enhance code clarity. Until next time!


* This newsletter was sourced from this Tutorials Dojo Article.

Thanks for the useful information Jon. You and your team work hard to make very useful and helpful information available to people who may want to learn more about it, and I thank you guys for that!

要查看或添加评论,请登录

Jon Bonso的更多文章

社区洞察

其他会员也浏览了