AWS_EN

Serverless apps using SAM

Using SAM to create a serverless application with API Gateway and Lambda

In the following pages, we have covered how to create a serverless app using API Gateway and Lambda, and now we would like to reproduce a similar configuration using SAM.

SAM (Serverless Application Model) is a framework for developing serverless application applications provided by AWS.

The AWS Serverless Application Model (SAM) is an open-source framework for building serverless applications. It provides shorthand syntax to express functions, APIs, databases, and event source mappings… During deployment, SAM transforms and expands the SAM syntax into AWS CloudFormation syntax, enabling you to build serverless applications faster.

AWS Serverless Application Model

In addition to the above, one of the features of SAM is local testing.

Use the AWS Serverless Application Model Command Line Interface (AWS SAM CLI) sam local command to test your serverless applications locally.

Using sam local

This simplified syntax and local testing allows developers to speed up app development and focus on the app’s logic rather than the app’s infrastructure.

In this page, we will check SAM by following the steps in the official AWS tutorial Tutorial: Deploying a Hello World application.

Environment

Diagram of serverless app using SAM.

We will build the same environment as in Serverless Application using Lambda and API Gateway.

We will create the application with the following settings.

  • Application name: fa-006
  • Runtime environment for Lambda functions: Python 3.8

Scenario

The following process will be followed.

  1. SAM App creation
  2. Test SAM app locally
  3. Deploy SAM app

SAM application creation

Create an application with AWS SAM CLI.

If you have not installed this tool, please refer to Installing the AWS SAM CLI.

$ sam init
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1
What package type would you like to use?
        1 - Zip (artifact is a zip uploaded to S3)
        2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 1

Which runtime would you like to use?
        1 - nodejs12.x
        2 - python3.8
        3 - ruby2.7
        4 - go1.x
        5 - java11
        6 - dotnetcore3.1
        7 - nodejs10.x
        8 - python3.7
        9 - python3.6
        10 - python2.7
        11 - ruby2.5
        12 - java8.al2
        13 - java8
        14 - dotnetcore2.1
Runtime: 2

Project name [sam-app]: fa-006

Cloning app templates from https://github.com/aws/aws-sam-cli-app-templates

AWS quick start application templates:
        1 - Hello World Example
        2 - EventBridge Hello World
        3 - EventBridge App from scratch (100+ Event Schemas)
        4 - Step Functions Sample App (Stock Trader)
        5 - Elastic File System Sample App
Template selection: 1

    -----------------------
    Generating application:
    -----------------------
    Name: fa-006
    Runtime: python3.8
    Dependency Manager: pip
    Application Template: hello-world
    Output Directory: .Code language: Bash (bash)

SAM configuration file

Place the SAM template file at the following URL.

awstut-fa/006/template.yaml at main · awstut-an-r/awstut-fa
Contribute to awstut-an-r/awstut-fa development by creating an account on GitHub.

Template file points

We will cover the key points of each template file to configure this environment.

Lambda functions are defined with AWS::Serverless::Function type

Define a Lambda function in SAM.

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.8
      Events:
        HelloWorld:
          #Type: Api
          Type: HttpApi
          Properties:
            Path: /hello
            Method: getCode language: YAML (yaml)

In CloudFormation, the Type property specifies the type of resource to be created. Normally, when defining a Lambda function, “AWS::Lambda::Function” is used, but if you follow the SAM notation, it will be “AWS::Serverless::Function”.

In the CodeUri property, specify the directory PATH where the script to be executed is located. PATH can be specified relative to this template file. The PATH can be specified relative to the main template file. In this case, it means that the script will be placed in the “hello_world” directory, which is located in the same location as the main template file.

The Handler property is a parameter that specifies the actual function to be executed when the Lambda function is called. By specifying “app.lambda_handler”, it means that the lambda_handler function in the app.py file located in the “hello_world” directory will be executed.

The Runtime property is a parameter that specifies the runtime environment for the function. In this case, we will specify Python 3.8 to run the function.

The Events property allows you to define the events associated with this function.

Specifies the events that trigger this function. Events consist of a type and a set of properties that depend on the type.

AWS::Serverless::Function

This time, we will use this property to define the API Gateway associated with this function.

You can specify the resource to be created in the Type property in the Events property.

Object describing properties of this event mapping. The set of properties must conform to the defined Type.

Type: S3|SNS|Kinesis|DynamoDB|SQS|Api|Schedule|CloudWatchEvent|EventBridgeRule|CloudWatchLogs|IoTRule|AlexaSkill|Cognito|HttpApi|MSK|MQ

EventSource

Since we will be creating an HTTP API type API Gateway, specify “HttpApi”.

Specify the various parameters of the resource to be created in the Properties property.

The Path and Method properties are parameters related to the API Gateway root. In this case, we will specify that this function will be executed when “/hello”, the endpoint to be created, is accessed by GET.

The function to be executed is as follows.

import json

def lambda_handler(event, context):
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world from Awstut !"
        }),
    }
Code language: Python (python)

For details, please refer to the following page.

Test SAM app locally

As mentioned at the beginning of this article, the sam local command can be used to locally test the SAM application you have created. In this article, we will introduce three local testing methods.

sam local invoke

The AWS official description of the sam local invoke command is as follows

Use the AWS Serverless Application Model Command Line Interface (AWS SAM CLI) sam local invoke subcommand to initiate a one-time invocation of an AWS Lambda function locally.

Using sam local invoke

Use the sam local invoke command to perform local testing.

$ sam local invoke HelloWorldFunction
Invoking app.lambda_handler (python3.8)                                                                                        
Local image is out of date and will be updated to the latest runtime. To skip this, pass in the parameter --skip-pull-image    
Building image...........................................................................................................................................................................................................
Using local image: public.ecr.aws/lambda/python:3.8-rapid-x86_64.                                                              
                                                                                                                               
Mounting /[app-dir]/fa-006/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside   
runtime container                                                                                                              
START RequestId: b6c66d3b-532d-4ae5-97ea-d265e04c4064 Version: $LATEST
END RequestId: b6c66d3b-532d-4ae5-97ea-d265e04c4064
REPORT RequestId: b6c66d3b-532d-4ae5-97ea-d265e04c4064  Init Duration: 0.16 ms  Duration: 137.87 ms     Billed Duration: 138 msMemory Size: 128 MB     Max Memory Used: 128 MB
{"statusCode": 200, "body": "{\"message\": \"hello world from Awstut !\"}"}

SAM CLI update available (1.109.0); (1.101.0 installed)
To download: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.htmlCode language: Bash (bash)

I was able to successfully execute the sam local invoke command with HelloWorldFunction specified.
Looking at the execution result, it is indeed returning a JSON string containing “hello world from Awstut ! is returned.

Thus, using SAM, local testing can be performed on a per-Lambda function basis.

sam local start-api

AWS公式では、sam local start-apiコマンドは以下の通りに説明されています。

Use the AWS Serverless Application Model Command Line Interface (AWS SAM CLI) sam local start-api subcommand to run your AWS Lambda functions locally and test through a local HTTP server host. This type of test is helpful for Lambda functions that are invoked by an Amazon API Gateway endpoint.

Using sam local start-api

Use the sam local start-api command to perform local testing.

First, start a local test server.

$ sam local start-api
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]                                                               
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on 
your functions, changes will be reflected instantly/automatically. If you used sam build before running local commands, you    
will need to re-run sam build for the changes to be picked up. You only need to restart SAM CLI if you update your AWS SAM     
template                                                                                                                       
2024-02-11 08:25:16 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:3000
2024-02-11 08:25:16 Press CTRL+C to quitCode language: Bash (bash)

A local test server is now up and running.

Then access this test server using the curl command.
The Lambda function created in this SAM app is tied to the URL /hello, so we access it accordingly.

$ curl http://127.0.0.1:3000/hello
{"message": "hello world from Awstut !"}Code language: Bash (bash)

There was indeed a response.
Looking at the execution result, it is indeed returning a JSON string containing “hello world from Awstut ! is returned.

Check the log output to the local server during this access.

Invoking app.lambda_handler (python3.8)                                                                                        
Local image is up-to-date                                                                                                      
Using local image: public.ecr.aws/lambda/python:3.8-rapid-x86_64.                                                              
                                                                                                                               
Mounting /[app-dir]/fa-006/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside   
runtime container                                                                                                              
START RequestId: 7b672c4b-c7ec-44a3-aa6f-ce0e36d98a57 Version: $LATEST
END RequestId: 7b672c4b-c7ec-44a3-aa6f-ce0e36d98a57
REPORT RequestId: 7b672c4b-c7ec-44a3-aa6f-ce0e36d98a57  Init Duration: 0.46 ms  Duration: 271.65 ms     Billed Duration: 272 msMemory Size: 128 MB     Max Memory Used: 128 MB

No Content-Type given. Defaulting to 'application/json'.                                                                       
2024-02-11 08:26:55 127.0.0.1 - - [11/Feb/2024 08:26:55] "GET /hello HTTP/1.1" 200 -Code language: plaintext (plaintext)

It is indeed readable that HelloWorldFunction is being executed.

Thus, using SAM, local testing can be performed even at the API Gateway level.

sam local start-lambda

The AWS official description of the sam local start-api command is as follows

Use the AWS Serverless Application Model Command Line Interface (AWS SAM CLI) sam local start-lambda subcommand to invoke your AWS Lambda function through the AWS Command Line Interface (AWS CLI) or SDKs.

Using sam local start-lambda

Use the sam local start-lambda command to perform local testing.

First, start a local test server.

$ sam local start-lambda
Starting the Local Lambda Service. You can now invoke your Lambda Functions defined in your template through the endpoint.     
2024-02-11 08:29:43 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:3001
2024-02-11 08:29:43 Press CTRL+C to quitCode language: Bash (bash)

A local test server is now up and running.

Then access this test server using the AWS CLI.

$ aws lambda invoke --function-name HelloWorldFunction --endpoint-url http://127.0.0.1:3001 ./out.txt
{
    "StatusCode": 200
}Code language: Bash (bash)

Success.
The test uses the general aws lambda invoke command, but the key is to specify the local server in the endpoint-url.

The following are the execution results during local testing.

$ cat ./out.txt 
{"statusCode": 200, "body": "{\"message\": \"hello world from Awstut !\"}"}Code language: Bash (bash)

Looking at the execution result, it is indeed returning a JSON string containing “hello world from Awstut !” is returned.

Invoking app.lambda_handler (python3.8)                                                                                                                             
Local image is up-to-date                                                                                                                                           
Using local image: public.ecr.aws/lambda/python:3.8-rapid-x86_64.                                                                                                   
                                                                                                                                                                    
Mounting /[app-dir]/fa-006/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside runtime container                      
START RequestId: 4bd88094-9223-4cc8-ade6-955dfae03361 Version: $LATEST
END RequestId: 4bd88094-9223-4cc8-ade6-955dfae03361
REPORT RequestId: 4bd88094-9223-4cc8-ade6-955dfae03361  Init Duration: 0.36 ms  Duration: 177.11 ms     Billed Duration: 178 ms Memory Size: 128 MB     Max Memory Used: 128 MB

2024-02-11 08:39:50 127.0.0.1 - - [11/Feb/2024 08:39:50] "POST /2015-03-31/functions/HelloWorldFunction/invocations HTTP/1.1" 200 -Code language: plaintext (plaintext)

It is indeed readable that HelloWorldFunction is being executed.

Thus, with SAM, local testing can also be done in a format that can be accessed using the AWS CLI.

SAM Application Deployment

Build and deploy with AWS SAM CLI.

First, let’s build.

$ sam build --use-container
Starting Build inside a container
Building codeuri: hello_world/ runtime: python3.8 metadata: {} functions: ['HelloWorldFunction']

Fetching amazon/aws-sam-cli-build-image-python3.8 Docker container image...................................................................................................................................................................................................................................................................
Mounting /your-directory/hello_world as /tmp/samcli/source:ro,delegated inside runtime container

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
    
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
Code language: Bash (bash)

By using the use-container option, you can build your application in a dedicated Docker container.

If your functions depend on packages that have natively compiled dependencies, use this option to build your function inside a Lambda-like Docker container.

sam build

In this case, since we are using Python 3.8 as the runtime environment, the same environment must be available locally to run the CLI. However, by using this option, the build is completed in the container, so there is no need to worry about the local environment.

Next, we will proceed to deploy the application.

$ sam deploy --guided

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

        Looking for config file [samconfig.toml] :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: fa-006
        AWS Region [us-east-1]: ap-northeast-1
        #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
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
        Save arguments to configuration file [Y/n]: y
        SAM configuration file [samconfig.toml]:   
        SAM configuration environment [default]: 

....

        Deploying with following values
        ===============================
        Stack name                   : fa-006
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Deployment s3 bucket         : [bucket-name]
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {}
        Signing Profiles             : {}

Initiating deployment
=====================
HelloWorldFunction may not have authorization defined.

Waiting for changeset to be created..

CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                LogicalResourceId                        ResourceType                             Replacement                            
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                    HelloWorldFunctionHelloWorldPermission   AWS::Lambda::Permission                  N/A                                    
+ Add                                    HelloWorldFunctionRole                   AWS::IAM::Role                           N/A                                    
+ Add                                    HelloWorldFunction                       AWS::Lambda::Function                    N/A                                    
+ Add                                    ServerlessHttpApiApiGatewayDefaultStage   AWS::ApiGatewayV2::Stage                 N/A                                    
+ Add                                    ServerlessHttpApi                        AWS::ApiGatewayV2::Api                   N/A                                    
-----------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:[accound-id]:changeSet/samcli-deploy1641285770/e5418e4b-792d-4e96-93ae-5d10a45ee858

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

...

CloudFormation outputs from deployed stack
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                                         
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                                                                                   
Description         Implicit IAM Role created for Hello World function                                                                                          
Value               arn:aws:iam::[account-id]:role/fa-006-HelloWorldFunctionRole-VBT1AK5MRG5J

Key                 HelloWorldApi                                                                                                                               
Description         API Gateway endpoint URL for Prod stage for Hello World function                                                                            
Value               https://25ypbm7one.execute-api.ap-northeast-1.amazonaws.com/hello

Key                 HelloWorldFunction                                                                                                                          
Description         Hello World Lambda Function ARN                                                                                                             
Value               arn:aws:lambda:ap-northeast-1:[account-id]:function:fa-006-HelloWorldFunction-qajs4WIMSN60
-----------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - fa-006 in ap-northeast-1
Code language: Bash (bash)

Deployment has been completed successfully.

From the deployment log, we can see that five resources have been created this time.

Also, from the output in the Outputs section, we can see that the API Gateway endpoint created this time is “https://25ypbm7one.execute-api.ap-northeast-1.amazonaws.com/hello”.

Access the SAM application

Now let’s actually access it.

https://25ypbm7one.execute-api.ap-northeast-1.amazonaws.com/hello
{"message": "hello world from Awstut !"}
Code language: Bash (bash)

We were able to successfully retrieve the results of the Lambda function execution.

As you can see, by using SAM, we were able to build a serverless application more concisely than with the normal CloudFormation notation.

(Reference) Details of various resources created by SAM

We will check the status of various resources of the application deployed with SAM.

As we saw at the beginning, SAM is a variant of CloudFormation, so deploying a SAM application will create a CloudFormation stack.

Although not included in this stack, Route and Integration of API Gateway resources have also been created.

Check the status of the stack creation from the AWS Management Console.

The list of resources created by SAM

Although not directly defined in the template file, you can see that the Permission for API Gateway to call the Lambda function and the IAM role to be granted to the Lambda function are also automatically created.

The contents of Permission are as follows.

Permission automatically generated by SAM

The conditions for calling the Lambda function are defined. Only calls from the API Gateway created this time and from the GET method with the URL /hello will be allowed.

The following is the IAM role that has been created.

IAM roles automatically created by SAM

You can see that the AWS managed policy AWSLambdaBasicExecutionRole has been attached, which means that the minimum privileges for executing Lambda functions have been granted.

Although not included in this stack, API Gateway root and integration resources have also been created.

First is integration.

Integration automatically generated by SAM

You can see that the Lambda function we created is associated with it.

Next is the route.

Routes automatically generated by SAM

The GET method of /hello is associated with the previous integration. The combination of these settings will allow the Lambda function to be executed when the API Gateway is accessed.

Summary

We found that SAM allows us to build serverless applications more concisely than the usual CloudFormation notation.
We also found that SAM provides a rich set of local testing methods.
This simplified syntax and local testing allows developers to speed up the development of their apps and focus on the logic of the app rather than the infrastructure of the app.

タイトルとURLをコピーしました