Sitemap
BIP xTech

We use exponential technologies to power end-to-end digital solutions, supporting data-driven transformation and scaling up responsiveness to business evolution. We increase the effectiveness and efficiency of our clients’ processes with Data and Technologies.

Follow publication

A Practical Guide to Surviving AWS SAM

7 min readJul 17, 2019

AWS SAM is an open-source framework that you can use to build serverless applications on AWS. Opposed to other tools, such as the serverless framework, SAM is an official AWS product — making it valuable to give it a try.

If you are new to the serverless world you may feel overwhelmed by definitions, tools, best practices. But don’t worry, once you start playing with it you will not be able to stop.

But I don’t want to dwell on other details so let’s start. You can find all the code on my GitHub

Setup

First thing to do is initializing our first AWS SAM project (ok it’s the second one but I’ll leave up to you the boring installation of all we need, but you can find more details on my GitHub page.

sam init --runtime python3.7 --name aws-sam

This command is very helpful since create the skeleton of our project

.
└── aws-sam
├── hello_world # code and requirements of our lambda function
│ ├── app.py
│ └── requirements.txt
├── tests # folder containing test code
│ └── unit
│ └── test_handler.py
├── event.json # API gateway event example
├── README.md
├── template.yaml # AWS SAM template
└── .gitignore

template.yaml file come with predefined a lambda function with an API gateway event attached to it

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: hello world aws sam
Globals:
Function:
Timeout: 3
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.7
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get

If you prefer you can directly create your project from yor preferred IDE supporting AWS Toolkit. I will use AWS Toolkit for PyCharm, and if you go to

File --> New Project... --> AWS Serverless Application

where you will find the basic configuration for your project

Press enter or click to view image in full size

Build

For building dependencies AWS SAM CLI comes with a built-in build command

sam build --template template.yaml

The command will create a .aws-sam folder containing our code packaged with dependencies installed from requirements.txt

For our example will look like this

.
└── .aws-sam
└── build
├── HelloWorldFunction
│ ├── HelloWorldFunction
│ │ ├── app.py
│ │ └── ... # packaged dependencies
└── template.yaml

As you can see the command recreates the original tree substituting the name of the folder with the name of the resource defined in the template. So folder hello_world in our project became folder HelloWorldFunction, like the name of the resource in template.yaml file.

Each of our lambda folder must contain a requirements.txtfile specifying required dependencies, you will have so maximum granularity specifying dependencies for each function but AWS SAM will have to install the dependencies for each lambda resulting in longer build time if your template contains an high number of lambda function.

Keep also in mind that all the content of the folder you specify in CodeUri will be packaged for our lambda, counting in the size limit of lambda deployment package.

Package

Now that all our dependencies have been downloaded we can package all in way that AWS lambda will accept our code. AWS SAM is an optimized cloudformation for serverless application so it comes with all the benefits (and pains) of cloudformation. One of the greatest advantage it’s the possibility to use the built-in package command.

sam package --template-file .aws-sam/build/template.yaml --s3-bucket artifact-bucket --s3-prefix aws-sam/versions/1 --output-template-file .aws-sam/build/template-packaged.yaml

This command package all our code, upload it on an existing S3 and updates our template CodeUri with the correct S3 key. Remember to use the build folder otherwise all our dependencies will be missing once deployed our function.

I suggest you to take advantage of the --s3-prefixparameter to create a clean structure also for yuor deployments, otherwise you will end with all our package in the root of our S3 bucket.

Our packaged template will look like this

AWSTemplateFormatVersion: '2010-09-09'
Description: hello world aws sam
Globals:
Function:
Timeout: 3
Outputs:
HelloWorldApi:
Description: API Gateway endpoint URL for Prod stage for Hello World function
Value:
Fn::Sub: https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/
HelloWorldFunction:
Description: Hello World Lambda Function ARN
Value:
Fn::GetAtt:
- HelloWorldFunction
- Arn
HelloWorldFunctionIamRole:
Description: Implicit IAM Role created for Hello World function
Value:
Fn::GetAtt:
- HelloWorldFunctionRole
- Arn
Resources:
HelloWorldFunction:
Properties:
CodeUri: s3://artifact-bucket/aws-sam/versions/1/b891a08245ed5940781e64b483cbcb14
Events:
HelloWorld:
Properties:
Method: get
Path: /hello
Type: Api
Handler: app.lambda_handler
Runtime: python3.7
Type: AWS::Serverless::Function
Transform: AWS::Serverless-2016-10-31

As you can see CodeUri path now points to an S3 key, containing our package.

Deploy

It’s now time to see our application working for real. As stated before we can use the utilities of cloudformation in particular we can leverage deploy command

sam deploy --stack-name hello-world-sam --template-file .aws-sam/build/template-packaged.yaml --capabilities CAPABILITY_IAM

As you can see we are telling sam to deploy our template-packaged.yaml template, the one generated from package command, CloudFormation will read the template and create all the resource defined within it.

We can check the correct deployment from AWS CloudFormation console

Press enter or click to view image in full size

Test

Till now we have assumed all our code and configurations are correct, once deployed all will work like a charm, but usually it’s not the case, testing it’s always an important step to keep in mind when your are developing an application. In the world of serverless testing strategies has changed a little focusing more on the integration rather than unit introducing new challenges.

Try to define a testing strategies for all the components of your application from template passing through the code till the roles your function will have once deployed.

We will roughly cover some of the major testing strategies for our application without digging into details, I just wanna start make you comfortable with the basics of AWS SAM, next parts will cover with major details this topic.

Let’s start with the validate command, utility letting you check whenever your template is syntactically valid:

sam validate --template template.yaml

It’s a really easy command that can saves time during deployment phase.

Passing to code we can use local invoke command that let you invoke locally your lambda handler with a mocked event passed from a json file or directly to the command.

sam local invoke --event event.json

You can also invoke your function directly from the template within Pycharm with AWS Toolkit

Press enter or click to view image in full size

And from Run/Debug configuration you can set basic information like AWS credential to be used, automatically loaded from AWS CLI configuration

Press enter or click to view image in full size

If you have created the project from CLI or you have added new function and you try to run a function you may incur in the following error

Press enter or click to view image in full size

This problem can be easily solved marking the folder containing your function as source root, this way Python interpreter will know where to find you function code.

Press enter or click to view image in full size

Another useful utility it’s the possibility to locally start an API gateway hosting all your function

sam local start-api

Now you can locally invoke your HTTP endpoint from localhost, with an API manager like Postman.

If you want to test your function within python you can use one of the testing libraries supported and locally invoke the lambda handler function. AWS SAM init preconfigure for you a tests folder containing an example.

Here i reported a slightly different version leveraging the event.json file instead of generating event directly from code.

import json
import pytest
from hello_world import app


@pytest.fixture()
def apigw_event():
""" Generates API GW Event"""
with open("../../event.json") as json_file:
return json.load(json_file)


def test_lambda_handler(apigw_event, mocker):
ret = app.lambda_handler(apigw_event, "")
data = json.loads(ret["body"])

assert ret["statusCode"] == 200
assert "message" in ret["body"]
assert data["message"] == "hello world!"
# assert "location" in data.dict_keys()

If you are experiencing problems with the import of your function from test folder check if sys path are correctly set.

Great you survived to AWS SAM! It’s not that difficult in the end but we have only scratched the surface of what SAM is capable of. So stay tuned for the second part of the tutorial. Thank you for reading.

More content at bip.xTech

BIP xTech
BIP xTech

Published in BIP xTech

We use exponential technologies to power end-to-end digital solutions, supporting data-driven transformation and scaling up responsiveness to business evolution. We increase the effectiveness and efficiency of our clients’ processes with Data and Technologies.

Paolo Fusari
Paolo Fusari

Write a response