Table of Contents
Overview of AWS SAM and its processes
AWS SAM stands for Serverless Application Model. It’s a serverless framework for AWS resources exclusively. It’s used to define, test, and deploy serverless applications. SAM templating may resemble CloudFormation — and rightfully so because CloudFormation lies underneath and takes care of the deployment part.
When you deploy our fully defined stack — lambda functions, roles, S3 buckets, serverless-native databases — you can test it while deployed in a cloud environment in the non-production stage (and it may incur charges). The development process could be faster and cheaper by running everything locally — and you will build such a setup in this article.
Requirements
Initializing a project
You can browse all templates or write from scratch using sam init
but we will start with the “Serverless API” template provided by AWS.
sam init --name my-sam-app --runtime nodejs14.x --app-template quick-start-web
Overview
Now, let’s have a quick look at template.yaml
which describes the setup. Your goal is to comprehend resources in just 20 seconds. All right, start!
Few CRUD functions and a DynamoDB Table. You don’t need to define API gateway resources and roles in this framework, making it much simpler than Terraform equivalent.
Trying to invoke events locally
You can check if functions are working by using mocked events.
Let’s choose getAllItemsFunction
function from the template and a related event from events/
. It should return an empty array because no items have been inserted yet.
sam local invoke getAllItemsFunction -e events/event-get-all-items.json
Unfortunately, we get:
Invoke Error {"errorType":"ResourceNotFoundException","errorMessage":"Requested resource not found"...
It happens because we do not have DynamoDB locally.
Look at these few extracted lines from the function handler src/handlers/get-all-items.js
:
AWS SDK (imported in the first line) depends on execution context — and magically finds the related DynamoDB service when being deployed in the cloud. Locally, it finds nothing.
Adding DynamoDB locally
Run DynamoDB in Docker by using the official AWS image. Here’s the command:
docker run -p 8000:8000 amazon/dynamodb-local
Adjust function handler
Change the docClient
declaration in the first lines of src/handlers/get-all-items.js
It will change the connection used depending on AWS’s SAM environment, then point to the local DynamoDB.
We are using host.docker.internal
instead of localhost
because the AWS SAM event launcher is already in a docker container. This way, we get the address of the host machine from a guest container. Mind blown, I know.
Create a table locally
We are using the SimpleTable
resource, which represents one table in DynamoDB. It is automatically created or used (if it exists), but we must create it locally.
Use table name SampleTable
so that the local table is automatically compliant with template.yaml
and existing handlers.
Do the same for attributes and keys — use the id
defined in template.yaml
aws dynamodb create-table --table-name SampleTable --attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH --billing-mode PAY_PER_REQUEST --endpoint-url http://localhost:8000
Check if it’s created with the following:
aws dynamodb list-tables --endpoint-url http://localhost:8000
Run the test event again
$ sam local invoke getAllItemsFunction -e events/event-get-all-items.json[...]"statusCode":200,"body":"[]"
Request processed. The body is indeed an empty array. You did it! 🏆
Now you can keep developing your lambda functions with the database connected. If you are ready to go live, you can do it with sam deploy
.
In this article, you have:
- Understood AWS SAM basics
- Added DynamoDB integration locally
- Made local development setup ready for your beautiful app
In some scenarios, it takes too much effort to build a fully integrated local environment for development in serverless. There have to be changes in the code base that switch variables depending on whether they are executed locally or remotely.
It may result in inconsistencies that escalate into code that works perfectly locally but fails in the cloud. Consider if you need the whole integration locally or if CI/CD should take care of integration testing.
On top of that, DynamoDB has a smooth local integration because AWS provides the docker image. The setup with other, more uncommon resources can be cumbersome.
What serverless framework are you using and how does it simplify your development?
Let me know in the comments below!