Increase AWS CDK Lambda development speed by testing locally with AWS SAM
Tags: aws, cdk, sam, lambda
Published: 2021-09-20 14:45:31

This is a cross-post from <https://medium.com/contino-engineering/increase-your-aws-cdk-lambda-development-speed-by-testing-locally-with-aws-sam-48a70987515c>

Git repo with all code completed:<https://github.com/chrishart0/aws-cdk-sam-demo>

This article explains how to locally test, with [AWS SAM](https://aws.amazon.com/serverless/sam/)(Serverless Application Model), a Lambda function + API Gateway created with [AWS CDK](https://aws.amazon.com/cdk/)(Cloud Development Kit).

When using AWS CDK for your infrastructure as code, it can be a pain to figure out how to efficiently test your Lambda functions. Deploying your code to AWS with cdk deploy for every change is slow, having to run a deploy for every code change is not ideal. Luckily it is straightforward to use AWS SAM to test your function locally. 

For scenarios where local dev isn’t feasible, get faster deployments to Lambda with [`cdk deploy --hotswap`](https://github.com/aws/aws-cdk/blob/master/packages/aws-cdk/README.md#hotswap-deployments-for-faster-development)

[This gif demonstrates using SAM to test Lambda + API Gateway generated with CDK.](https://github.com/chrishart0/aws-cdk-sam-demo/blob/master/static_content/sam-cdk-demo.gif)


Steps 0-2 help you set up a fresh CDK project. **If you already have a CDK project which creates a lambda function and API Gateway, skip ahead to step 3.**

## 0) Prerequisites, Assumptions, and Environment


* NPM Installed
* Python Installed
* If you don’t have AWS CDK installed follow this guide: <https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html>
* If you don’t have AWS SAM installed, follow this guide: <https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html>

## 1) Initialize a CDK project
*Note:* If this is your first time using AWS CDK with Python, I recommend you try out the CDK Workshop from AWS: <https://cdkworkshop.com/30-python/20-create-project/100-cdk-init.html>

*⚠️ Optionally: you can clone the completed repo here and skip to step 3*

Create a directory for your project and cd into it
```
$ mkdir aws-sam-cdk-demo
$ cd aws-sam-cdk-demo
```

Then, initialize your CDK project
```
$ cdk init app --language python
```

Create and source a python virtual environment
```
$ python3 -m venv .venv
$ source .venv/bin/activate
```

Install CDK requirements 
```
$ pip install -r requirements.txt
```

Run CDK synth to ensure everything is setup correctly
```
$ cdk synth
```

You should see a small CloudFormation template get created with only the CDKMetadata resource and some conditions:
![cdk synth output screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygnmkizg64s4rlrurmd3.png)

## 2) Create a Lambda function
In this example, I’ll be making an API that provides a greeting from a list of greetings I have hardcoded.

Create a directory for the lambda code and create a file for the code
```
$ mkdir lambda
$ touch lambda/greeting_generator.py
```

Go ahead and add some code to your function. You can copy the code from my function and tweak it as you see fit:< https://github.com/chrishart0/aws-cdk-sam-demo/blob/master/lambda/greeting_generator.py>

### Install the lambda and API Gateway constructs
Add `aws-cdk.aws-lambda` and `aws-cdk.aws-apigateway` as lines to `requirements.txt`
![requirements.txt image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzauyjif1rgq73jdcuju.png)

Run the command to install the the lambda and API Gateway constructs.
```
$ pip install -r requirements.txt
```

### Time to add lambda and API Gateway to your stack
Open the stack file.

If you aren't familiar with CDK then the stack file may be confusing, this is where infrastructure is defined in a CDK project. [See here for reference stack file.](https://github.com/chrishart0/aws-cdk-sam-demo/blob/master/aws_sam_cdk_demo/aws_sam_cdk_demo_stack.py) The stack file was created by `cdk init`, it follows the naming scheme `same_as_your_parent_dir/same_as_your_parent_dir_stack.py`
* Example: Parent folder which init was run in is `aws-sam-cdk-demo`
* `aws_sam_cdk_demo/aws_sam_cdk_demo_stack.py`
* Example in GitHub: <https://github.com/chrishart0/aws-cdk-sam-demo/blob/master/aws_sam_cdk_demo/aws_sam_cdk_demo_stack.py>
![Stack file example location](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wg2j60d7wuxpn48ody4p.png)

Import lambda at the top of the stack file referenced above. 
```
from aws_cdk import (
    core,
    aws_lambda as _lambda,
    aws_apigateway as apigateway,
)
```

Add code to your stack to generate a lambda function.
```
greeting_function = _lambda.Function(
            self, 'greeting_handler',
            runtime=_lambda.Runtime.PYTHON_3_9,
            code=_lambda.Code.asset('lambda'),
            handler='greeting_generator.handler',
        )
```

Add code for the API Gateway. Ensure the handler is the same as the variable for the lambda function.
```
greeting_apg = apigateway.LambdaRestApi(
            self, 'greeting_endpoint',
            handler=greeting_function,
            description="Greeting API endpoint",
        )
```

The stack should now look like the image below:
![Completed stack](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpcf4qvih5a0h99i7269.png)

*Tip: Add links back to the CDK docs in your code; this will save you a lot of time hunting for the right page in the future.*

Run `cdk synth` to ensure everything compiles. You should now see more resources in the CloudFormation output in your terminal.

## 3) Test that lambda function locally with SAM
Here is where things start to get a little… nutty 🐿️ (get it, like the [SAM squirrel mascot](https://aws.amazon.com/serverless/build-a-web-app/)???)

*If you already have a CDK application with a lambda function start here!*

Synthesize a template and write it to `template.yaml`
```
$ cdk synth --no-staging > template.yaml
```

Test the API with SAM
```
$ sam local start-api
```

In your browser or in another terminal hit the endpoint `http://127.0.0.1:3000/`
![start API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/or94rpbiqoa73cto14ih.png)

You can change the code of your lambda function on the fly, no need to restart SAM. Edit the source code in the `lambda/` dir and call the endpoint again.
![changes on the fly](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t2skvzt69mqfdoxi76er.png)

You can also test individual invocations with simulated events, this is ideal if you are not using API Gateway.
```
$ sam local invoke functionName -e event.json
```

## 🎉🎉🎉 Congratulations 🎉🎉🎉
You can now use this very simple strategy to test your Lambda + API Gateway in your own CDK project or use this example project as a starting point.