AWS Compute Blog

Better together: AWS SAM and AWS CDK

Today AWS is announcing the public preview of AWS Serverless Application Model CLI (AWS SAM CLI) support for local development and testing of AWS Cloud Development Kit (AWS CDK) projects. AWS SAM and AWS CDK are both open-source frameworks for building applications using infrastructure as code (IaC). AWS SAM is template-based using JSON or YAML, while the AWS CDK uses languages such as Python or Node.

Before today, you could use the AWS SAM CLI to build locally, test, and package serverless applications defined using AWS CloudFormation or AWS SAM templates. With this preview release, you can use AWS SAM CLI to build, test, and in the future, package applications defined using the AWS CDK.

Support for the AWS CDK is currently in preview and the team is asking for your feedback and submissions. The goal is for both communities to help improve the local development process using AWS SAM CLI. No bug is too small. No feature request is too large to submit to the open source repository.

Walkthrough

The following steps demonstrate how to build a serverless application with AWS CDK and test it locally with AWS SAM CLI. The app translates text into multiple languages with the following process:

  1. The user sends the request with a string of text and the desired languages.
  2. The AWS Lambda function uses Amazon Translate to translate the string into the desired languages.
  3. The translations are placed onto an Amazon EventBridge event bus.
  4. The translations are returned to the user through an API Gateway response.
  5. A Lambda function is invoked to save the translations to an Amazon DynamoDB table.
Application diagram

Application diagram

Prerequisites

The following is required to run this demo:

Because this is a preview release of the AWS SAM CLI, it is installed side by side with the regular AWS SAM CLI. To use the regular version of AWS SAM, use the sam command. To use this preview version, use sam-beta-cdk.

Deploy the application

AWS SAM can test Lambda functions locally without deployment, but in order to test against resources such as DynamoDB or EventBridge I must deploy them first. The first steps are to clone the application and prepare the CDK environment:

  1. Clone the application to your local machine.
    git clone https://github.com/aws-samples/aws-sam-support-aws-cdk cdk-translator
  2. Change to the project directory.
    cd cdk-translator
  3. Install dependencies for the AWS CDK. Note, this is for the infrastructure only.
    npm install
  4. Configure your account and region for CDK deployment
    cdk bootstrap

The next step is to install the dependencies for the Lambda functions and then deploy. At this time, AWS SAM CLI supports the AWS Lambda construct library to create Lambda functions for all of the supported runtimes. However, AWS CDK also offers the aws-lambda-nodejs and aws-lambda-python constructs to handle automatic dependency management for those languages. Support for these additional constructs is forthcoming.

With the Lambda construct, the AWS CDK expects dependencies to be manually installed for each function before deployment. However, with this new feature, AWS SAM manages the dependencies for you with the sam build command. During the sam build process, AWS SAM creates a CloudFormation template using cdk synth. AWS SAM then builds the application artifacts including installing the dependencies and compiling if necessary. The resulting package is an AWS CDK Cloud Assembly that CDK uses to deploy.

To deploy the translation application with this process, continue with the following commands:

  1. Use AWS SAM to prepare the deployment artifacts.
    sam-beta-cdk build
  2. Deploy the application. When prompted with “Do you wish to deploy these changes (y/n)?” Enter Y.
    cdk deploy -a .aws-sam/build

After a few minutes, the application is deployed. You will notice output that looks similar to the following:

Output from CDK deploy

Output from CDK deploy

Local environments

Before testing locally, configure the application environment variables for AWS SAM. Each of the Lambda functions has an environment variable attached. For example, the GetTranslationFunction has the name of the DynamoDB table it reads from.

Lambda construct example

Lambda construct example

To pass these variables to the local invocations, create an environment variables file. To create this file, use the function identifier and the environment variable name and value. In the previous example, the function identifier is GetTranslationFunction. Putting this together with the output values for TranslationsTable and TranslationsBus and the environments variable file will look similar to this:

Environment variables file example

Environment variables file example

Create this file with your information and name it locals.json.

Local testing

Now that your backend services are deployed, it’s time to run some local tests to see if everything is working. Remember, even though you are invoking the Lambda functions locally, they interact with the services you deployed in your development account. Additionally, as you make changes to the code, run sam build to reflect those changes.

sam local invoke

The first test is to invoke the PutTranslationFunction locally. I created a mock event for each Lambda function. These events are located in the events directory. Run this command passing in the mock event and the local environment file:

sam-beta-cdk local invoke CdkDayStack/PutTranslationFunction -e events/putTranslation.json -n locals.json
SAM local invoke results

SAM local invoke results

AWS SAM mounts the AWS CDK asset for the PutTranslationFunction Lambda function and runs it locally. The function makes a request to Amazon Translate in the cloud. When it receives a response, it first creates a translation event on the EventBridge bus in the cloud. Then it returns all the translations as the response to the local client. The EventBridge rule then runs asynchronously in the cloud, which invokes the SaveTranslationFunction Lambda function. This saves each translation as a separate record in the DynamoDB table.

Use AWS SAM to invoke the GetTranslationFunction locally to verify that the records exist.

sam-beta-cdk local invoke CdkDayStack/GetTranslationFunction -e events/getTranslation.json -n locals.json

You should receive a response similar to when creating the translation previously. Use the sam logs command to check the logs of the SaveTranslationFunction, which ran in the cloud. Run the following command using the physical name of the function, which is shown in the outputs from the previous AWS CDK deployment.

sam-beta-cdk logs -n [function-name];

The response looks similar to the following:

SAM logs results

SAM logs results

sam local start-api

While the local invoke command directly invokes a Lambda function, the local start-api command emulates invoking a function through a local API Gateway endpoint. Use this command to start an endpoint that you can test with a local client.

sam-beta-cdk local start-api -n locals --warm-containers EAGER

AWS SAM creates an endpoint for each of the Lambda functions that is associated with an API. Adding the warm-containers flag with the EAGER option
tells AWS SAM to keep the containers active for subsequent requests, which speeds up local testing.

To test the local endpoint, open a second terminal window and run the following:

curl --location --request POST 'http://localhost:3000' --header 'Content-Type: application/json' --data-raw '{"text":"This is my translator built with AWS CDK and AWS SAM","languages":["de","fr"]}'

Then run the following to list all translations posted to the database:

curl --location --request GET 'http://localhost:3000'

The application returns a list of the original requests in English. To get a list of all the translations for a specific request, choose an id and run the following:

curl 'http://localhost:3000/[your-id-number]'
Results for getting translations locally

Results for getting translations locally

You can update the code while the local API remains active. When you make a GET request to the root of the API, the application returns a list of the original requests in English. The payload looks like this:

Original request results

Original request results

However, since all the original requests are in English, you can remove the language property. To do this, open src/get-translation/app.js, uncomment the line, “deletedata.language” and save the file.

Code change example

Code change example

Once the file is changed, run sam build to update the code.

sam-beta-cdk build

AWS SAM rebuilds the code and prepares it for testing without having to rerun the start-api command. The AWS SAM CLI recognizes the code change and reloads the container for the updated Lambda function on the following invocation.

sam local start-lambda

The final test is to run a local emulator of the Lambda service and invoke the function directly using an SDK or the AWS CLI. Start the local emulator with the following command:

sam-beta-cdk local start-lambda -n locals.json

AWS SAM starts the emulator and exposes a local endpoint for the AWS CLI or a software development kit (SDK) to call. Currently, this service requires the logical name of the function rather than the AWS CDK function identifier. To get the logical name of the function, open the .aws-sam/build/CdkDayStack directory. Each function has its directory, and the directory name is the logical name of the function.

Folder structure for built files

Folder structure for built files

With start-api still running, run the following command to invoke this function locally with the AWS CLI:

aws lambda invoke --function-name [function logical-name] --endpoint-url http://127.0.0.1:3001/ response.json

The AWS CLI invokes the local function and returns a status report of the service to the screen. The response from the function itself is in the response.json file.

Conclusion

With AWS SAM CLI native support for AWS CDK, developers have more options when choosing their preferred framework. In this post, I show how to use the AWS SAM CLI to test locally and develop serverless applications seamlessly within an AWS CDK project. No longer is the AWS SAM CLI just for AWS SAM; instead, AWS SAM and AWS CDK are better together.

Better together: SAM and CDK

Better together: SAM and CDK (Pancakes otter artwork by Clea Allen & Matthew Dorrian)

For more serverless learning resources, visit Serverless Land.

#ServerlessForEveryone