Install AWS SAM CLI and Execute AWS Lambda functions locally using SAM CLI

June 20, 2019  5 minute read  

Learn how to install AWS SAM CLI and invoke AWS Lambda functions on your local machine using AWS SAM CLI.

Steps to Run Lambda Locally

You will need to install AWS CLI, AWS SAM CLI and Docker to execute a Lambda function locally. If you already have AWS CLI installed, you can skip to step 2.

This is to assume you have AWS CLI installed. If not, you can follow steps on AWS CLI installation document to install AWS CLI.

1. Installing AWS CLI

You need to have at least Python 2.6+ or Python 3.3+ to install AWS CLI. The following is the command to install AWS CLI.


$ pip3 install awscli --upgrade --user

$ aws --version
aws-cli/1.16.77 Python/3.6.7 Darwin/17.7.0 botocore/1.12.67

1.5 Configure for AWS CLI

First, open AWS IAM Users console to retrieve your aws_access_key and aws_secret_access_key. Note that you can download your key value pair only once. If you lose it, you will have to recreate.

To configure, include your credentials in your machine namely creating these two files in your root folder: ~/.aws/credentials and ~/.aws/config. First, change directory to .aws by using the command below based on your OS.

MacOS:


$ ls  ~/.aws

Windows:


C:\> dir "%UserProfile%\.aws"

credentials

Then, in ~/.aws/credentials, include your aws_access_key and aws_secret_access_key like the following syntax.


[default]
aws_access_key_id=id_value
aws_secret_access_key=key_value

config

In ~/.aws/config, include AWS configuration options such as region.


[default]
region=us-west-2
output=json

2. Installing AWS SAM CLI

Depending on your machine types, the steps to install are different. The following steps only cover MacOS and Windows.

MacOS

On MacOS, you can use homebrew to install AWS SAM CLI by using the following commands.


# Add brew tap
$ brew tap aws/tap

# Install aws-sam-cli from brew tap
$ brew install aws-sam-cli

# Verify that SAM is installed
$ /home/homebrew/.homebrew/bin/sam

# Check installed SAM version
$ sam --version

Windows

  1. On Windows, you can install AWS SAM CLI using MSI files provided by AWS. Choose the correct MSI file based on your Windows version:
  2. Run sam --version to verify that you have successfully installed AWS SAM CLI.

sam --version

AWS SAM CLI

If you run sam, you can see SAM user guide like below:


$ sam
Usage: sam [OPTIONS] COMMAND [ARGS]...

  AWS Serverless Application Model (SAM) CLI

  The AWS Serverless Application Model extends AWS CloudFormation to provide
  a simplified way of defining the Amazon API Gateway APIs, AWS Lambda
  functions, and Amazon DynamoDB tables needed by your serverless
  application. You can find more in-depth guide about the SAM specification
  here: https://github.com/awslabs/serverless-application-model.

Options:
  --debug    Turn on debug logging to print debug message generated by SAM
             CLI.
  --version  Show the version and exit.
  --info
  --help     Show this message and exit.

Commands:
  package   Package an AWS SAM application. This is an alias for 'aws
            cloudformation package'.
  logs      Fetch logs for a function
  deploy    Deploy an AWS SAM application. This is an alias for 'aws
            cloudformation deploy'.
  build     Build your Lambda function code
  init      Initialize a serverless application with a...
  validate  Validate an AWS SAM template.
  publish   Publish a packaged AWS SAM template to the AWS Serverless
            Application Repository.
  local     Run your Serverless application locally for...
  

3. Install Docker

Docker is needed by AWS SAM CLI to invoke Lambda functions locally. You can follow instructions on Docker website to install Docker.

  1. Docker Desktop for Mac
  2. Docker Desktop for Windows

This is the error message that you will see when you run sam local invoke without Docker.


sam local invoke -e event.json 
Error: Running AWS SAM projects locally requires Docker. 
Have you got it installed?

4. Prepare Lambda Payload

Now, you should prepare payload JSON object that will be passed to Lambda when invoking Lambda locally. Normally, request parameters are included in queryStringParameters, pathParameters or body. You can modify complete Lambda proxy integration event included below to simulate different requests.

Depending on the Lambda functions, you may need only part of the complete JSON object. Most of the time, you only need to modify the following few objects:

  1. Query String Parameters
    "queryStringParameters": {
      "option": "myOption",
    }
    
  2. Path Parameters
    "pathParameters": {
      "action": "invoke"
    }
    
  3. Body
    "body": "{\r\n\t\"a\": 1\r\n}",
    
  4. Resource and Path. They are the same your API paths.
    "resource": "/{proxy+}",
    "path": "/hello/world",
    
  5. If you use Cognito Authorizer. You can modify information of the requester via requestContext’s authorizer object to mock the right user accessing your lambda.
    "requestContext": {
       "authorizer": {
           "claims": {
               "email": "abc@gmail.com",
               "sub": "3aaf36de-fe9f-4531-b1c1-75707ae79377"
           }
       }
    }
    

Complete Lambda Proxy Integration event:

{
  "resource": "/{proxy+}",
  "path": "/hello/world",
  "httpMethod": "POST",
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "cache-control": "no-cache",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Desktop-Viewer": "true",
    "CloudFront-Is-Mobile-Viewer": "false",
    "CloudFront-Is-SmartTV-Viewer": "false",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Viewer-Country": "US",
    "Content-Type": "application/json",
    "headerName": "headerValue",
    "Host": "gy415nuibc.execute-api.us-east-1.amazonaws.com",
    "Postman-Token": "9f583ef0-ed83-4a38-aef3-eb9ce3f7a57f",
    "User-Agent": "PostmanRuntime/2.4.5",
    "Via": "1.1 d9842f7680bd.cloudfront.net (CloudFront)",
    "X-Amz-Cf-Id": "pn-PWItl0gdeJky8tqsg8iS_sgsKD1A==",
    "X-Forwarded-For": "54.240.196.186, 54.182.214.83",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https"
  },
  "multiValueHeaders":{
    "Accept":[
      "*/*"
    ],
    "Accept-Encoding":[
      "gzip, deflate"
    ],
    "cache-control":[
      "no-cache"
    ],
    "CloudFront-Forwarded-Proto":[
      "https"
    ],
    "CloudFront-Is-Desktop-Viewer":[
      "true"
    ],
    "CloudFront-Is-Mobile-Viewer":[
      "false"
    ],
    "CloudFront-Is-SmartTV-Viewer":[
      "false"
    ],
    "CloudFront-Is-Tablet-Viewer":[
      "false"
    ],
    "CloudFront-Viewer-Country":[
      "US"
    ],
    "Content-Type":[
      "application/json"
    ],
    "headerName":[
      "headerValue"
    ],
    "Host":[
      "gy415nuibc.execute-api.us-east-1.amazonaws.com"
    ],
    "Postman-Token":[
      "9f583ef0-ed83-4a38-aef3-eb9ce3f7a57f"
    ],
    "User-Agent":[
      "PostmanRuntime/2.4.5"
    ],
    "Via":[
      "1.1 d9842f7680bd.cloudfront.net (CloudFront)"
    ],
    "X-Amz-Cf-Id":[
      "pn-PWItl0gdeJky8tqsg8iS_sgsKD1A=="
    ],
    "X-Forwarded-For":[
      "54.240.196.186, 54.182.214.83"
    ],
    "X-Forwarded-Port":[
      "443"
    ],
    "X-Forwarded-Proto":[
      "https"
    ]
  },
  "queryStringParameters": {
    "name": "me",
    "multivalueName": "me"
  },
  "multiValueQueryStringParameters":{
    "name":[
      "me"
    ],
    "multivalueName":[
      "you",
      "me"
    ]
  },
  "pathParameters": {
    "proxy": "hello/world"
  },
  "stageVariables": {
    "stageVariableName": "stageVariableValue"
  },
  "requestContext": {
    "accountId": "12345678912",
    "resourceId": "roq9wj",
    "stage": "testStage",
    "requestId": "deef4878-7910-11e6-8f14-25afc3e9ae33",
    "identity": {
      "cognitoIdentityPoolId": null,
      "accountId": null,
      "cognitoIdentityId": null,
      "caller": null,
      "apiKey": null,
      "sourceIp": "192.168.196.186",
      "cognitoAuthenticationType": null,
      "cognitoAuthenticationProvider": null,
      "userArn": null,
      "userAgent": "PostmanRuntime/2.4.5",
      "user": null
    },
    "resourcePath": "/{proxy+}",
    "httpMethod": "POST",
    "apiId": "gy415nuibc"
  },
  "body": "{\r\n\t\"a\": 1\r\n}",
  "isBase64Encoded": false
}

5. Invoke Lambda Locally

The command to invoke Lambda locally is sam local invoke and -e flag is used to specify the path to the Lambda event.


$ sam local invoke -e event.json

When it is run, it will look something like this:


$ sam local invoke MyLambda -e event.json

2019-06-20 11:11:09 Invoking index.handler (python3.7)
2019-06-20 11:11:09 Found credentials in shared credentials file: 
~/.aws/credentials

Fetching lambci/lambda:python3.7 Docker container image......
2019-06-20 11:11:11 Mounting /Users/myProject as /var/task:ro,
delegated inside runtime container
START RequestId: 52fdfc07-2182-154f-163f-5f0f9a621d72 Version: $LATEST
...

Summary

With AWS SAM CLI set up, you can invoke Lambda functions locally. Other than that, you can also use AWS Cloud9 to develop and invoke Lambda functions.

Support Jun

Thank you for reading!    Support JunSupport Jun

Support Jun on Amazon US

Support Jun on Amazon Canada

If you are preparing for Software Engineer interviews, I suggest Elements of Programming Interviews in Java for algorithm practice. Good luck!

You can also support me by following me on Medium or Twitter.

Feel free to contact me if you have any questions.

Comments