AWS SAM template is a thin abstraction of a CloudFormation template to develop and deploy lambda by a AWS tool, SAM (Serverless Application Model). It has shorter syntax compared to writing infrastructure as code with CloudFormation. We still do a little bit of learning when it comes to writing SAM templates. Using sam init
will create a template, so it is a good starting point. Then we can build the template according to our needs.
Quick Example
This creates Lambda function, IAM role, API Gateway, DynamoDB table.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'ts-simple-api-proxy-with-sam
Sample SAM Template for ts-simple-api-proxy
'
Resources:
TsSimpleProxyApiFunction: # (1) Creates Lambda function
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: main.example
Runtime: nodejs14.x
Events:
TsSimpleProxy:
Type: Api # (2) Creates API Gateway
Properties:
Path: /get-users
Method: get
Policies: # (3) Creates IAM Role
# We can choose from a list of policy templates which are specific to SAM
# See: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html
- DynamoDBReadPolicy:
TableName: !Ref ProductTable
- SSMParameterReadPolicy:
ParameterName: mock-parameter
ProductTable: # (4) Creates DynamoDb table
Type: AWS::Serverless::SimpleTable
SAM Resources
We can use both CloudFormation Resources and SAM specific resources. At the moment, there are 7 serverless resource types supported by SAM.
- AWS::Serverless::Function
- AWS::Serverless::Api
- AWS::Serverless::HttpApi
- AWS::Serverless::SimpleTable
- AWS::Serverless:::LayerVersion
- AWS::Serverless::Application
1. AWS::Serverless::Function
This creates a lambda function.
MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: index.handler
Runtime: nodejs14.x
Description: Example Lambda Function
MemorySize: 1024
Timeout: 15
Tracing: Active|PassThrough
Events:
TsSimpleProxyApi:
Type: HttpApi
Properties:
Path: /
Method: get
Policies:
- DynamoDBReadPolicy:
TableName: !Ref ProductTable
Metadata:
# Leaving blank will use the default build system
# We can set BuildMethod to makefile to use a MakeFile directed build in this example.
BuildMethod: nodejs12.x | makefile
At the moment there are 15 event sources.
- S3
- SNS
- Kinesis
- DynamoDB
- SQS
- Api
- HttpApi
- Schedule
- CloudWatchEvent
- CloudWatchLogs
- IoTRule
- AlexaSkill
- Cognito
- EventBridgeRule
- MSK
For the IAM Policies, there are over 70+ pre-configured one. If you cannot find one, we can use CloudFormation syntax to create custom one.
2. AWS::Serverless::Api
This is where we can create Api Gateway to build REST API. You can use OpenAPI to define it and refer to the swagger file.
TsSimpleProxyApi:
Type: AWS::Serverless::Api # Short hand Api works, too.
Properties:
StageName: prod
DefinitionUri: ./swagger.yml
3. AWS::Serverless::HttpApi
This is V2 of REST API (supposed to be faster, lower cost and easy to use compared to Api) for creating REST APIs.
TsSimpleProxyApi:
Type: AWS::Serverless::HttpApi # or just HttpApi
Properties:
CorsConfiguration:
AllowMethods:
- GET
- POST
AllowOrigins:
- http://localhost:8080
- http://another.domain.com
4. AWS::Serverless::SimpleTable
This is to create a DynamoDB table with Primary key id, Dynamic capacity and AWS managed encryption.
MyTable:
Type: AWS::Serverless::SimpleTable
Properties:
TableName: my-table
PrimaryKey:
Name: id
Type: String
ProisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
Tags:
Department: Engineering
AppType: Serverless
5. AWS::Serverless::LayerVersion
Layer to share code across multiple lambda functions. We can build layers accordingly as an option.
MyLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: static-data
Description: Static data layer for app
ContentUri: layer/
CompatibleRuntimes:
- nodejs12.x
LicenseInfo: 'MIT'
RetentionPolicy: Retain
Metadata:
BuildMethod: nodejs12.x | makefile
6. AWS::Serverless::Application
It allows to use an external application and pull it in.
MyApplication:
Type: AWS::Serverless::Application
Properties:
Location:
ApplicationId: 'arn:aws:serverlessrepo:...'
SemanticVersion: 1.0.0
Parameters:
StringParameter: parameter-value
IntegerParameter: 2
MyApplication:
Type: AWS::Serverless::Application
Properties:
Location: https://s3.amazonaws.com/bucket/tmpl.yaml
7. AWS::Serverless::StateMachine
For creating step functions.
MySampleStateMachine:
Type: AWS::Serverless::StateMachine
Properties:
DefinitionUri: sfdn/MyStateMachine.asl.json
Role: arn:aws:iam:::role/service-role/MyRole
DefinitionSubstitutions:
MyFunctionArn: !GetAtt MyFuction.Arn
MyDDBTable: !Ref TransactionTable
Globals
We can define Global parameters for multiple lambda functions to share. It makes SAM templates smaller by re-using attributes throughout.
Globals:
Function:
Runtime: nodejs12.x
Handler: index.handler
Timeout: 15
MemorySize: 1024
Layers:
- arn:aws::2222222:layer:aws-sdk:6
Environment:
Variables:
TABLE_NAME: MyTable
Building Reusable Templates
1. Parameters
To deploy to different environments, we can use parameters that can be passed through SAM CLI.
Parameter types support the below:
- Sting
- Number
- List
- CommaDelimitedList
- AWS-Specific parameter types
- AWS SSM or AWS Secrets Manager parameter types
Parameters:
DomainName:
Type: String
Description: Domain name for API
ZoneId:
Type: String
Description: Zone ID if exists.
Default: none
CertArn:
Type: String
Description: Certificate ARN if exists.
Default: none
DbEngine:
# Example of using AWS parameter values
Type: AWS::SSM::Parameter::Value<String>
Default: /myApp/DbEngine
Now we can use parameters inline.
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Runtime: nodejs12.x
Handler: app.lambdaHandler
Environment:
Variables:
DB_ENGINE: !Ref DbEngine
# We can use inline resolver to get the value
DB_VERSION: '{{resolve:ssm:/myApp/DbVersion:1}}'
DB_NAME: '{{resolve:secretsmanager:/myApp/DbName}}'
...
2. Pseudo parameters and intrinsic functions
These are in-built, most commonly used parameters that come with SAM template.
- AWS::AccountId
- AWS::NotificationARNs
- AWS::NoValue
- AWS::Partition
- AWS::Region
- AWS::StackId
- AWS::StackName
- AWS::URLSuffix
Of course, we can use CloudFormation's intrinsic functions
- Fn::Base64
- Fn::Cidr
- Fn::And
- Fn::Equals
- Fn::If and so on...
Then, we can combine these.
HttpApiGateway:
Type: AWS::Serverless::HttpApi
Properties:
Domain:
DomainName: !Ref DomainName
CertificateArn: !If [CreateCert, !Ref GeneratedCert, !Ref CertArn]
Route53:
HostedZoneId: !If [CreateZone, !Ref GeneratedZone, !Ref ZoneId]
1. About template.yaml
Once SAM builds the function, template.yaml
in the .aws-sam/build
folder takes precedence.
2. Debugging locally with SAM CLI in VS Code
With Node.js
- Create a debug configuration in VSCode
- Add a breakpoint in the code
- Invoke lambda function using start-api, start-lambda or invoke lambda.
- Attach the debuggerc