The AWS Serverless Application Model: A One-Stop-Shop for your serverless apps

-

It won’t surprise you when I say that the cloud train has left the station a while ago and is gaining more and more speed every day.

Because this trend doesn’t seem to stop it is important to be able to act fast on your changing environment to meet your customers demand with the least effort and time involved. The most obvious way to achieve this is to be as cloud native as possible. This means that you have to aim to use the building blocks that your cloud provider provides. One of these building blocks the Amazon AWS cloud offers, is the Serverless Application Model.
In this blogpost I will explain and demonstrate the basics this framework has to offer.

What is the Serverless Application Model?

 

The AWS Serverless application model is a framework that can be used to build serverless applications. This framework consist of 2 components:

  • The AWS SAM template specification

This specification is used to define your serverless application. It provides a clean and simple syntax to describe all necessary components to make your serverless application. The AWS SAM template specification is related and shares syntax with AWS Cloudformation.

  • The AWS SAM command line interface

The AWS SAM CLI can be used to build serverless applications that you define using the template specification. It also enables you to verify the templates written and invoke lambda functions locally. The CLI can also be used to package and deploy serverless applications to the AWS cloud.

Why should you use AWS SAM?

Using AWS SAM provides a lot of benefits regarding the development of serverless applications on the AWS cloud:

  • Single-deployment configuration. All required components are defined in one template.
  • Extension of AWS Cloudformation. AWS SAM is an extension of AWS Cloudformation which brings us these reliable deployment capabilities for free.
  • Built-in best practices. AWS SAM can be used to deploy your required infrastructure components as configuration. This enables you to check-in your template definition into your VCS and apply software development best practises like code reviews and such.
  • Local debugging and testing: The AWS SAM makes it possible to locally build , test and debug your serverless applications your have defined in your SAM template. With the help of Docker it is also possible to locally test your application against other infrastructure components like DynamoDB.
  • Deep integration with development tools. The AWS SAM makes it fairly simple to setup a Code deploy pipeline to build and deploy your serverless application on every vcs change.

A Simple yet complete REST-API

To demonstrate the capabilities of the SAM, we are going to create a REST-API that exposes CRUD actions on a DynamoDB. This app will cover most of the basic functionalities the Serverless Application Model provides

The high-level services that are part of AWS SAM are:

  • Lambdas
  • API Gateway
  • DynamoDB Tables

For more servies you can add other resources as specified in the Cloudformation specification.

Lambdas

Lambdas are the one of the most pure serverless component: It empowers a developer to be able to focus on writing the business logic only without the need to worry about boilerplate and infrastructure. Just upload your code/ binary to s3 and configure the lambda with the required instructions regarding environment variables and/ or credentials and you are good to go. The best part is that you only have to pay for the time your lambda is actually doing work! Our app will consist of several lambdas which will ensure the correct data is stored and retrieved from storage.

How AWS Lambda Works

API Gateway

In order to access the business logic that we put in our lambdas that cover the app functionality, we need to have a way to interact with this functionality from the internet. The most obvious way to do that is by deploying an API Gateway. An API Gateway can be configured to invoke various services available within the AWS landscape, like for example Lambdas. It supports various authentication mechanisms, out-of-the-box request logging and more advanced features like request throttling. The API Gateway can do some transformations before forwarding the request to the service of destination too. This feature can be very powerful. For example: when your lambdas evolve faster than your api users can keep up with, you can use transformations to convert the incoming request to the datamodel the lambda expects. Or vice versa: transform the response of your lambda to match the model of the defined api contract.

API Gateway how it works

Persistence

The AWS SAM framework has support for DynamoDB which is profiled as a serverless document database solution ‘for any scale’TM. Since our requirements are not that fancy, DynamoDB will fit our requirements just fine: we only have to store our entries somehow and we need to be able to fetch them by specific criteria and be able to update an entry.

Putting it all together

We will create/ deploy the following resources using the Serverless Application Model:

  • A few Lambda Functions
  • An API Gateway
  • A DynamoDB table

 

I’ve already created an application to illustrate the capabilities of the Serverless Application Model framework and it is available on GitHub. This application consists of 3 Lambdas that use DynamoDB to retrieve, store and update entries.

The Template

Now the Serverless application model magic happens. The template is the key component in this framework and will make sure AWS will create the desired resources in the cloud. Lets highlight some parts of the template than can be found in the before mentioned GitHub repository

 

An excerpt of the template.yml file

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  This template describes the resources to be deployed for the Todo app
  
Globals:
  Function:
    Timeout: 3

Resources:
  ListTodosFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: functions/list-todos
      Handler: list-todos.lambdaHandler
      Runtime: nodejs12.x
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Select [1, !Split ['/', !GetAtt DynamoTodosTable.Arn]]
      Environment:
        Variables:
          TABLE_NAME: !Select [1, !Split ['/', !GetAtt DynamoTodosTable.Arn]]
      Events:
        ListTodos:
          Type: Api
          Properties:
            Path: /list
            Method: get

Most of this template.yml looks quite similar to a Cloudformation template, and in a SAM-template the Resources section is the most important/ interesting part too.

Lambdas

We see that there is a function definition of type AWS::Serverless::Function that points to function code. Besides the type this is similar to a Lambda definition in a Cloudformation template. However, this function definition also defines an event of type Api which is an additional property the SAM framework provides.
When an event is defined of type Api, the Serverless Application Model will deploy an API gateway for you! As can be seen in the template.yml, there is also a Path defined. The framework will automatically configure the API Gateway to route all HTTP GET requests for /list to the Lambda function this event is defined for!

To find out what all available options for functions are, please refer to the resource specification.

DynamoDB

As mentioned earlier, the Lambda functions require a DynamoDB table to store, update and retrieve entries. As you can see the template also contains a resource definition with name DynamoTodosTable and type AWS::Serverless::SimpleTable. This is the most simple way to define a DynamoDB table requiring minimal configuration:

 

  DynamoTodosTable:
    Type: AWS::Serverless::SimpleTable # if you want to define a more complex table, use AWS::DynamoDB::Table
    TableName: !Ref TableName
    PrimaryKey:
      Name: todo-id
      Type: String
    BillingMode: PROVISIONED
    ProvisionedThroughput:
      ReadCapacityUnit: 1
      WriteCapacityUnits: 1
    Tags:
      AppType: Serverless

The DynamoDB simple table definition can be configured via various parameters, like providing a meaningful table name, setting the number of provisioned read and write units and what the primary key look like.

Deployment

 

To deploy the application, we have to first build the application. Assuming you have installed the SAM CLI (if not, follow the instructions here), execute the sam build command:

 

$ sam build
Building resource 'ListTodosFunction'
Running NodejsNpmBuilder:NpmPack
Running NodejsNpmBuilder:CopyNpmrc
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc
Building resource 'UpdateTodoFunction'
Running NodejsNpmBuilder:NpmPack
Running NodejsNpmBuilder:CopyNpmrc
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc
Building resource 'CreateTodoFunction'
Running NodejsNpmBuilder:NpmPack
Running NodejsNpmBuilder:CopyNpmrc
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
$

This command creates an application that is ready to be deployed by Cloudformation. You can review the result of this action in the folder .aws-sam/build.
Now it is time to deploy the application to the AWS Cloud. To do so, execute the sam deploy --guided command in a terminal window. The --guided flag will cause the SAM CLI to prompt with some questions. Luckily, the answers can be saved for future use in a samconfig.toml file and will be picked up by the SAM CLI automatically for future executions.

 

% sam deploy --guided

Configuring SAM deploy
======================

        Looking for samconfig.toml :  Not Found
        Reading default arguments  :  Success

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [todos-app]: todos-app
        AWS Region [eu-west-1]: eu-west-1
        Parameter TableName [my-todos]: my-todos
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: y
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: Y
        Save arguments to samconfig.toml [Y/n]: Y

        Looking for resources needed for deployment: Found!


Initiating deployment
=====================

Waiting for changeset to be created..

CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                                                               LogicalResourceId                                                                       ResourceType                                                                          
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
* Modify                                                                                CreateTodoFunction                                                                      AWS::Lambda::Function                                                                 
* Modify                                                                                ListTodosFunction                                                                       AWS::Lambda::Function                                                                 
* Modify                                                                                ServerlessRestApi                                                                       AWS::ApiGateway::RestApi                                                              
* Modify                                                                                UpdateTodoFunction                                                                      AWS::Lambda::Function                                                                 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:eu-west-1:*********:changeSet/samcli-deploy15******/338abafc-adb7-489f-b677-1f87c4d6ab31


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]:

The procedure will pause when it is ready for deployment, and wants you to confirm the deployment. It is possible to enable auto confirmation in the samconfig.toml file.

Deploy this changeset? [y/N]: y

CloudFormation events from changeset
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                                                    ResourceType                                                      LogicalResourceId                                                 ResourceStatusReason                                            
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
UPDATE_IN_PROGRESS                                                AWS::Lambda::Function                                             ListTodosFunction                                                 -                                                               
UPDATE_IN_PROGRESS                                                AWS::Lambda::Function                                             UpdateTodoFunction                                                -                                                               
UPDATE_IN_PROGRESS                                                AWS::Lambda::Function                                             CreateTodoFunction                                                -                                                               
UPDATE_COMPLETE                                                   AWS::Lambda::Function                                             UpdateTodoFunction                                                -                                                               
UPDATE_COMPLETE                                                   AWS::Lambda::Function                                             CreateTodoFunction                                                -                                                               
UPDATE_COMPLETE                                                   AWS::Lambda::Function                                             ListTodosFunction                                                 -                                                               
UPDATE_COMPLETE_CLEANUP_IN_PROGRESS                               AWS::CloudFormation::Stack                                        todos-app                                                         -                                                               
UPDATE_COMPLETE                                                   AWS::CloudFormation::Stack                                        todos-app                                                         -                                                               
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

CloudFormation outputs from deployed stack
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                                                                                                                                              
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 TodoApi                                                                                                                                                                                                                                          
Description         API Gateway endpoint URL for Prod stage for the todos functions                                                                                                                                                                                  
Value               https://8wthljigzd.execute-api.eu-west-1.amazonaws.com/Prod/                                                                                                                                                                                     
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - todos-app in eu-west-1


As you can see the url where we can find our deployed endpoints is printed in the console.

Validating our deployment

Let’s store a todo by executing a HTTP POST request using curl:

$ curl -i --location --request POST 'https://8wthljigzd.execute-api.eu-west-1.amazonaws.com/Prod/' \ --header 'Content-Type: application/json' \ --data-raw '{ "activity": "Write a Blog about AWS SAM", "done": false }' 
HTTP/2 201 
x-created-item-id: fZbbSVdm-

Lets use curl again to issue an update on the created todo, where we use the identifier as path variable:

$ curl -i --location --request PUT 'https://8wthljigzd.execute-api.eu-west-1.amazonaws.com/Prod/update/fZbbSVdm-' \ --header 'Content-Type: application/json' \ --data-raw '{"activity": "Write a Blog about AWS SAM","done": true}' 
HTTP/2 204

Now, to check if the todo is updated, let’s list all the todo’s we have in our database:

$ curl -i https://8wthljigzd.execute-api.eu-west-1.amazonaws.com/Prod/list
HTTP/2 200 

[{"id":"fZbbSVdm-","activity":"Write a Blog about AWS SAM","done":true}]

As we can see the list endpoint returns exactly what we expected to see: An updated todo item!