Introduction to AWS SAM (Serverless Application Model)
Tags: aws, sam, serverless, iac
Published: 2024-01-23 17:57:30

I've decided to repost an article I originally published on my blog [here](https://playingaws.com/posts/how-to-create-serverless-applications-with-sam) two years ago, but this isn't just a simple repost. After rereading the original pieces, labeled as '22 min read' and '20 min read,' I realized updates were necessary. Consequently, I've thoroughly reviewed, updated, and reorganized all the content to ensure it remains relevant and up-to-date.

I will create an `AWS SAM series` featuring 3 articles:

- Introduction to AWS SAM (Serverless Application Model)
- How to create serverless applications with AWS SAM (Serverless Application Model)
- How to add CI/CD to my SAM project

This will be my first series of articles here.

---

## Introduction

The first thing to understand is the relationship between serverless applications and AWS SAM, followed by a review of the basics.

### What is a serverless application?

A **serverless application** is more than just a Lambda Function. It is a `combination of` Lambda functions, event sources, APIs, databases, and other `resources that work together to perform tasks`.

### What is AWS SAM?

The AWS `Serverless Application Model` (AWS SAM) is an [open-source framework](https://github.com/aws/serverless-application-model) that you can use to build serverless applications on AWS. SAM is an `extension of AWS CloudFormation` but SAM is streamlined and specifically designed for Serverless resources.

> SAM is the specific IaC solution of AWS for defining and deploying serverless applications.

### Benefits of SAM

- **Local Testing and Debugging**
  - With the `aws sam cli` you can execute and test your serverless applications on your local environment (by mounting a docker image and running the code)
- **Extension of AWS Cloud Formation**
  - You get reliability on the deployment capabilities
  - You can use the `SAM yaml template` with all of the resources that are available in CloudFormation
- **Single Deployment Configuration**
  - You can easily manage all your necessary resources in one single place that belongs to the same stack
- **Built-in best practices**
  - You can define and deploy your Infrastructure as Config
    - you can enforce code reviews
    - you can enable safe deployments through `CodeDeploy`
    - you can enable tracing by using `AWS X-Ray`
- **Deep integration with development tools**
  - AWS Serverless Application Repository: discover new applications
  - AWS Cloud9 IDE: For authoring, testing, and debugging. [I have written a post about Cloud9; you can find it here](/posts/mastering-aws-cloud9-for-docker-deployment/)
  - CodeBuild, CodeDeploy, and CodePipeline: To build a deployment pipeline
  - AWS CodeStar: To get started with a project structure, code repository, and a CI/CD pipeline that's automatically configured for you

### Basics

> We will use `NodeJS` as programming language. However, as AWS Says in the [FAQs](https://aws.amazon.com/serverless/sam/faqs/), you can use AWS SAM to build serverless applications that use any runtime supported by AWS Lambda.

To understand the code structure of the SAM projects, five files are particularly important:

- Common to all the programming languages:

  1. **template.yaml**: This file contains the AWS SAM template that defines your application's AWS resources.
  2. **events**/file.json: `events` folder contains the invocation events that you can use to invoke the function.
- Depends on the programming language (in this case `NodeJS`), so it will be different in each case (but the idea is the same):
  3. **src**/handlers/file.js: `src` folder contains the code for the application's Lambda Function.
  4. **__tests**\__/unit/handlers/file.test.js: `test` folder contains the unit tests for the application code.
  5. **package.json**: This file of NodeJS contains the application dependencies and is used for the `sam build`. If you are using Python language instead of NodeJS, the file will be **requirements.txt**.


### AWS SAM template anatomy

This is the structure of the `template.yaml`.

```yaml
# The AWSTemplateFormatVersion identifies the capabilities of the template
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/format-version-structure.html
AWSTemplateFormatVersion: '2010-09-09'
# Optional: description
Description: >-
  Any text here.
  Multi-line

# Transform section specifies one or more macros that AWS CloudFormation uses to process your template
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html
Transform: AWS::Serverless-2016-10-31  

# Optional: Globals section defines properties that are common to all your serverless functions and APIs
Globals:
  Function:
    Timeout: 3
    MemorySize: 128
    Tracing: Active
    Tags:
      iac: SAM

# Optional: provides additional information about the template
Metadata:
  template metadata

# Optional: Values to pass to your template at runtime (when you create or update a stack).
Parameters:
  set of parameters

# Optioal: A mapping of keys and associated values that you can use to specify conditional parameter values, similar to a lookup table
Mappings:
  set of mappings

# Optional: conditions that control whether certain resources are created or whether certain resource properties are assigned a value during stack creation or update
Conditions:
  set of conditions

# Resources declares the AWS resources that you want to include in the stack.
# Resources section can contain a combination of AWS CloudFormation resources and AWS SAM resources
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html
Resources:
  set of resources

# Optional: The values that are returned whenever you view your stack's properties
Outputs:
  set of outputs
```

More information [here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy.html).

### Prerequisites

- AWS CLI
  - [how to install it](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
  - [how configure it](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html)
- AWS SAM CLI ([here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html))

## Example of SAM application

Let's start reviewing one example of the SAM application to show some options about what we can do here.

I will show you the part of the `template.yaml` file which affects the specific service.

> It's important to remember that you can incorporate CloudFormation resources into our SAM template. However, AWS SAM offers specific resources that are specially tailored for creating Lambda Functions, API Gateway, AppSync, DynamoDB, Step Functions, among several other services. All the relevant information can be found [here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-resources-and-properties.html).

### Example of Lambda Function

The first special type, and more important, is the `AWS::Serverless::Function`, which you should use to create Lambda Functions (more information [here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)).

```yaml
Resources:
  # Each Lambda function is defined by properties:
  # https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction

  # This is a Lambda function config associated with the source code: hello-from-lambda.js
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/hello-from-lambda.helloFromLambdaHandler
      Runtime: nodejs14.x
      Architectures:
        - x86_64
      MemorySize: 128
      Timeout: 100
      Description: A Lambda function that returns a static string.
      Policies:
        # Give Lambda basic execution Permission to the helloFromLambda
        - AWSLambdaBasicExecutionRole
```

### Adding an API Gateway

To add the API Gateway resource you can use the specific type of `AWS::Serverless::Api` (more information [here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html)).

```yaml
Resources:
  ...
  BasicAWSApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      Name: Basic AWS Api Gateway resource
      StageName: poc
      ...
```

You can also add a trigger in the Lambda Function updating the section `Events`:

```yaml
Resources:
  HelloWorldFunction:
    Properties:
      ...
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /
            Method: get
```

And you should create in `events` folder the `json` definition of the method:

```json
{
    "httpMethod": "GET"
}
```

### Adding an scheduled event to the Lambda Function

Including a scheduled event to the Lambda Function is quite similar to adding an API.

```yaml
Resources:
  HelloWorldFunction:
    Properties:
      ...
      Events:
        CloudWatchEvent:
          Type: Schedule
          Properties:
            Schedule: cron(0 * * * ? *)
```

And you should create in `events` folder the `json` definition of the rule:

```json
{
  "id": "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c",
  "detail-type": "Scheduled Event",
  "source": "aws.events",
  "account": "",
  "time": "1970-01-01T00:00:00Z",
  "region": "us-west-2",
  "resources": [
    "arn:aws:events:us-west-2:xxxxxxxxxxxx:rule/ExampleRule"
  ],
  "detail": {}
}
```

### Adding the SNS topic resource

In this case, I will include the Lambda Function as a subscriber of my SNS topic.

```yaml
Resources:
  ...
  SnsTopicAsTriggerOfLambdaFunction:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: !Sub '${ResourcesName}'
      DisplayName : Topic used for trigger the lambda function
      Subscription:
        - Protocol: lambda
          Endpoint: !GetAtt HelloWorldFunction.Arn
      TracingConfig: Active
```

### Saving one property in the SSM Parameter Store

```yaml
Resources:
  ...
  MySnsTopicArnParameter:
      Type: AWS::SSM::Parameter
      Properties:
        Name: /general/sns/topic-test
        Type: String
        Value: !Ref SnsTopicAsTriggerOfLambdaFunction
```

### More examples

As you can see, you can add any resource using the usual `CloudFormation code` inside the `template.yaml` file.

> I recommend that you run `aws sam init` and try to create different projects from the templates.