Olá pessoal, tudo bem?
Hoje vamos falar sobre mais uma ferramenta que gosto muito e que facilita bastante a criação de aplicações serverless, o AWS Serverless Application Model (AWS SAM).
O que é o SAM?
O AWS SAM é um framework que oferece novos elementos para o CloudFormation específicos para serverless. Na realidade, ele é um superset do mesmo, pois estes novos componentes foram criados utilizando os transforms do CloudFormation.
Além destes novos elementos, o SAM fornece também uma CLI, utilizada para gerenciar todo o ciclo de vida das aplicações, desde a criação até o deploy.
O que há de novo no template?
Para ilustrar algumas diferenças, abaixo segue o exemplo de um template criado usando o SAM.
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Sample SAM Template for SamExample 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 Outputs: HelloWorldApi: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn
O exemplo acima é o template padrão do AWS SAM, criado com o projeto. Por ser simples, facilita a visualização da nova estrutura.
Como podemos ver, a primeira diferença no SAM está na linha 2, o Transform que ele utiliza para gerar o template final do CloudFormation.
Na linha 7, vemos um novo tipo de resource, o AWS::Serverless::Function
. Como veremos em mais detalhes a seguir, todos os tipos do SAM usam o namespace AWS::Serverless::*
.
O restante é praticamente idêntico ao CloudFormation, suportando funções intrínsecas, importvalue, e as demais features do mesmo.
Para entendermos um pouco melhor sobre sua estrutura, abaixo falaremos um pouco sobre cada novo tipo fornecido pelo framework.
Function – AWS::Serverless::Function
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
Como o nome sugere, Function representa Lambda functions. As propriedades que aparecem no exemplo representam:
- CodeUri: O local onde está o código da função Lambda;
- Handler: Quem é o handler que será o ponto de entrada da Lambda;
- Runtime: Qual a runtime da Lambda;
- Events: Aqui podemos definir quem é o gatilho (ou gatilhos) que irá disparar a função. Atualmente o SAM suporta S3, SNS, DynamoDB, Kinesis, SQS, API, Schedule, CloudWatchEvents, CloudWatchLogs, IoTRules, Cognito e Alexa Skills.
No exemplo acima, a Lambda será disparada através de um API Gateway, criada durante o deploy, quando efetuarmos um GET no path /hello
. Se tivermos mais de uma função no template, que tenha API como fonte de eventos, quando fizermos o deploy será criada apenas uma API Gateway contendo todos os endpoints relacionados a estes eventos.
API – AWS::Serverless::API
HelloWorldAPI: Type: AWS::Serverless::Api Properties: StageName: production DefinitionUri: mydefinition.yml EndpointConfiguration: REGIONAL Variables: ConnectionString: ProductionConnectionString
Se quisermos utilizar o Swagger para definirmos a estrutura da API Gateway, podemos usar o tipo API. No exemplo, as principais propriedades são:
- StageName: Define o nome do estágio da API Gateway;
- DefinitionUri: Uri com a definição do template do swagger;
- EndpointConfiguration: Tipo do endpoint da API (REGIONAL, PRIVATE ou EDGE);
- Variables: São as stage variables do estágio da API Gateway;
SimpleTable – AWS::Serverless::SimpleTable
HelloWorldTable: Type: AWS::Serverless::SimpleTable Properties: PrimaryKey: Name: productId Type: String ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 TableName: Products
O tipo SimpleTable, é uma versão simplificada de uma tabela do DynamoDB. Simplificada pois é possível definir apenas uma PrimaryKey, e nada mais. Inclusive, podemos remover todo o nodo Properties
, que valores default serão usados para criar a tabela.
LayerVersion – AWS::Serverless::LayerVersion
HelloWorldLayer: Properties: LayerName: HelloWorldLayer ContentUri: 's3://<mybucket>/sam-example-layer.zip' RetentionPolicy: Delete Description: Sam example Layer Version LicenseInfo: 'License information' CompatibleRuntimes: - python2.7 - python3.6 - python3.7
LayerVersion representa uma layer que pode ser compartilhada entre as funções Lambda.
Neste componente, podemos evidenciar as propriedades:
- ContentUri: Onde está localizado o conteúdo da layer;
- CompatibleRuntimes: Runtimes que são compatíveis com esta layer;
- RetentionPolicy: Apesar de estar definido como Delete no exemplo, deletando as versões anteriores da layer, o valor padrão é Retain, que faz com que à cada novo deploy, as versões anteriores permaneçam.
Application – AWS::Serverless::Application
HelloWorldApplication: Type: AWS::Serverless::Application Properties: Location: ApplicationId: 'arn:aws:serverlessrepo:us-east-1:012345678901:applications/sam-application-example' SemanticVersion: 1.0.0 Parameters: StringParameter: SAM Test TimeoutInMinutes: 10
Com o tipo Application, podemos aninhar outras aplicações à aplicação que estamos criando. Estas aplicações podem ser do AWS SAR (Serverless Application Repository) ou podem ser templates armazenados no S3. Este componente é bacana, pois facilita a reutilização de aplicações e componentes criadas por nós e outros desenvolvedores.
Sobre as propriedades mostradas no exemplo:
- Location: Como citei anteriormente, pode ser do SAR ou do S3. No exemplo, apontamos para o SAR. No S3, teríamos algo como:
Location: https://s3.amazonaws.com/<mybucket>/app.yaml
;
- Parameters: Os parâmetros enviados à aplicação;
- TimeoutInMinutes: Após a transformação, o tipo Application resulta em uma nested stack do CloudFormation. Este parâmetro indica o tempo que o CloudFormation irá esperar pela criação desta stack aninhada, antes de cancelar a operação.
Outros elementos importantes
Globals
Globals: Function: Timeout: 14 handler: app.lambda_handler
É possível definir um elemento Globals no template, onde definimos propriedades que são comuns a todas as funções Lambdas existentes no template.
No exemplo acima, estamos definindo o timeout e o caminho do handler de forma global.
Policies
Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.7 Policies: - EC2DescribePolicy: {} Events: HelloWorld: Type: Api Properties: Path: /hello Method: get
O AWS SAM possui diversos templates prontas de policies, para facilitar a construção das aplicações. Ela também permite a utilização de políticas gerenciadas e políticas inline (criadas no template), possibilitando bastante flexibilidade ao gerirmos o controle de permissões.
Para saber mais sobre estas templates, basta clicar aqui para acessar a documentação.
Criando um projeto
Falando um pouco agora sobre o SAM CLI, o primeiro passo é instalarmos o mesmo. A instalação pode ser ser feita seguindo está documentação: Instalando o AWS SAM CLI.
Em seguida, podemos criar um projeto com o comando:
sam init --runtime python3.7 --name sam-example
Basicamente, no comando acima ele irá criar um app chamado sam-example, usando o python3.7. É possível remover todos os argumentos do comando, executando apenas sam init
, e neste caso ele criar uma aplicação chamada sam-app, usando nodejs10.* como runtime.

Sobre a estrutura inicial do projeto, vale comentar um pouco sobre:
- events/*: Eventos de exemplo para serem usados em teste;
- hello_world/*: Contém o handler e os arquivos relacionados à Lambda HelloWorld;
- tests/*: Diretório para incluirmos testes;
- template.yaml: Template do AWS SAM.
Compilando o projeto
Para compilarmos um projeto do SAM, executamos o comando:
sam build
Como produto da compilação, o SAM gera um diretório chamado .aws-sam no root do projeto. Ali ele copia o arquivo de template, e cria um diretório para a função incluindo todas as dependências para executá-la.

Testando as aplicações localmente
Os testes locais são feitos através do comando sam local
. Nele temos algumas opções de execução:
- start-lambda: Inicia a lambda localmente em um endpoint, permitindo que executemos ela através do SDK ou do CLI.
- start-api: Simula uma API, permitindo que efetuemos testes usando HTTP;
- invoke: Executa a lambda localmente, apenas uma vez.
Existe outra opção no comando local
, chamada generate-event
. Esta opção cria exemplos de evento das fontes suportadas pelo SAM (S3, API, Kinesis, etc), para usarmos nos testes.
Publicando a aplicação
Quando a aplicação estiver pronta para ser publicada, precisamos executar dois passos:
1) Empacotar a aplicação
Para empacotar a aplicação, utilizamos a instrução:
sam package --s3-bucket sam-example
A execução deste comando irá gerar um pacote, enviá-lo para o S3 e fazer uma cópia do template, substituindo o sourceUri da função pelo caminho criado no S3. O novo sourceUri ficará similar ao exemplo abaixo (linha 4):
Resources: HelloWorldFunction: Properties: CodeUri: s3://sam-example/80d971cd7ef24874575dd3f2563888c7 Events: HelloWorld: Properties: Method: get Path: /hello Type: Api Handler: app.lambda_handler Runtime: python3.7 Type: AWS::Serverless::Function
2) Publicar a aplicação
Por fim, para publicarmos a aplicação com o SAM, executamos o comando:
sam deploy --template-file <template-file-location>.yaml --stack-name sam-example
Obrigatoriamente precisamos informar ambos os argumentos:
- template-file: Template gerado pelo comando package (com o sourceUri modificado);
- stack-name: O nome da stack do CloudFormation que será criada/atualizada.
Conclusão
Acredito que o framework mais conhecido e utilizado para este tipo de aplicação seja o Serverless Framework. Contudo, para aqueles que forem trabalhar com AWS, o SAM também é uma excelente opção para iniciar um projeto. Ele possui algumas de features avançadas, como canary deployment (que não comentei neste post, mas você pode acessar aqui), e executa sobre o CloudFormation.
Um abraço, e até a próxima!