The AWS blog gave me a very pleasant surprise the other day: AWS SAM Local is in public beta. It's a golang CLI project that's distributed via NPM.

SAM Local leverages Docker to run you code in local containers, and leverages the great work done by Michael Heart on LambCI for the container.

In this post I'll highlight the minimum number of steps to get up and running with SAM Local.

SAM

SAM Local builds upon AWS SAM: The Serverless Application Model. It was introduced in late 2016 and presents a simplified model for creating and deploying serverless applications. Oh, and the mascot is a magic construction squirrel:

SAM the Magic Construction Squirrel

It's a transformation layer on top of AWS CloudFormation that gives you a declarative way to define your serverless resources.

Using SAM instead of raw CloudFormation allows for a less verbose declaration of resources such as functions (Lambda), event sources (e.g. S3, API Gateway, etc), and database (DynamoDB).

A potential point of confusion for new users of SAM is that it is an open source standard, not an open source tool. While you can suggest and submit improvements to the standard (via the GitHub repo), the actual implementation is not open (because it depends on CloudFormation, which is an AWS service).

It's also important to note that SAM will not support non-serverless services. If you want to create other resources, just use CloudFormation in your SAM template! It all gets translated to CloudFormation in the end...

Installation

In order to get started you'll need to have Docker running in the background. On Mac OSX you should install that via Homebrew:

brew cask install docker

Once installed and run, you'll see the Docker icon in your tray, and it should be running:

Docker Tray Icon

Now that you've got the required dependencies, install the SAM Local tool itself:

npm install --global aws-sam-local

Once that's installed, you can access the command sam in your terminal.

Sample Project

To get started quickly we'll leverage the api-event-source sample projects in the SAM Local repo.
Clone the repo and go to the example directory:

git clone https://github.com/awslabs/aws-sam-local.git
cd aws-sam-local/samples/api-event-source

This project creates a single function with an API (i.e. HTTP) event source, so it simulates a Lambda function and an API Gateway endpoint.

At the top of the template.yaml file you can see the key difference with normal CloudFormation templates:

AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31

The Transform property tells CloudFormation how to handle the template, and allows you to use the SAM resource types.

All the function handler code (in index.js) does is return a 200 response with the string payload "OK".

Run

sam local start-api

If it's the first time you've run this command, the Docker container will be downloaded before running.

In the output you'll see the required container being run, and then listening for events as a HTTP endpoint that you can open in your local browser.

Not exciting, but working

On my development laptop it took a while for requests to respond, even though the actual compute time of the function (which is reported in the output) was very low:

2017/08/16 22:22:14 Invoking index.handler (nodejs6.10)
START RequestId: 0d3c5d51-c16e-19a9-2816-78fdeffb2f51 Version: $LATEST
END RequestId: 0d3c5d51-c16e-19a9-2816-78fdeffb2f51
REPORT RequestId: 0d3c5d51-c16e-19a9-2816-78fdeffb2f51  Duration: 8.15 ms       Billed Duration: 100 ms Memory Size: 128 MB     Max Memory Used: 29 MB

This is because of the overhead of spinning up the container (before it even touches your code) for each request. I found that giving the function more memory (the default is the lowest i.e. 124MB) sped up effective response time considerably. Hopefully that (i.e. cold starts) is something that can be improved in the future without having to throw memory at it.

If you only edit your function handler code (i.e. in index.js) you don't need to restart your service.
Changes to the template (i.e. template.yaml) do need a restart to take effect.

Sample Event

Before I would usually have to set up a logging function (i.e. one that just logs the event it receives to the console) with my chosen event source, and fire a few test events to it so that I had something to work with.

Now we can just run a command locally to get a sample event to work with. In this case we want an API test event, so we pass that as an argument:

sam local generate-event api

This will output the event (JSON) to your terminal. While interesting, it's not usable.
To save it so we can use it later, redirect the output to a file:

sam local generate-event api > event.json

Invoking

Now that we have a test event, we can do a one-off invocation of our function with the test event we've saved:

sam local invoke "ExampleFunction" -e event.json

This will give the function's output as a one-off.

START RequestId: 42949c86-df9a-1f85-6ed3-c399223e292f Version: $LATEST

{"statusCode":200,"body":"OK"}
END RequestId: 42949c86-df9a-1f85-6ed3-c399223e292f
REPORT RequestId: 42949c86-df9a-1f85-6ed3-c399223e292f  Duration: 11.16 ms      Billed Duration: 100 ms Memory Size: 128 MB     Max Memory Used: 28 MB

Any errors will be output to stderr.

Validate

Another one of the great time-saving features I was happy to see in SAM Local was the validate command.

If your template is using SAM (i.e. not just CloudFormation) and named template.yaml you can validate it with:

sam validate

This will give you feedback on your template's properties and formatting (e.g. YAML whitespace) without going through the package/deploy/test cycle, which is a big improvement to the development flow.

Help

All the commands take the -h/--help argument so that you can find out all their valid arguments and descriptions.

Look at his construction hat!

I'm really happy that the tooling around serverless applications is improving at such a rapid clip!