AWS SAM CLIでローカルAPIを起動してLambda関数をテストする方法

# はじめに
本記事ではaws sam cliを使用しローカルからLambdaを作成・デプロイする方法を記載します。


# AWS SAM CLIとは？
 > The SAM Command Line Interface (CLI) lets you locally build, test, and debug serverless applications defined by AWS SAM templates. SAM CLI provides a Lambda-like execution environment locally and helps you catch issues upfront. 

AWS SAM テンプレートで定義されたサーバーレスアプリケーションをローカルでビルド、テスト、デバッグするためのcli ツール。

https://aws.amazon.com/jp/serverless/sam/faqs/

# 環境
- python：Python 3.12.2

# AWS SAM CLIのインストール

下記ページを参考に任意のOSのインストーラをダウンロードし、AWS SAM CLI をインストールします。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/install-sam-cli.html

# サーバーレスプロジェクトの初期化

SAM CLI を使って新しいサーバーレスプロジェクトを作成します。

```
sam init
```

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/using-sam-cli-init.html


<details><summary>テンプレートを選択</summary>
提示される選択肢から任意のものを選択していきます。
最後にプロジェクトの名前を入力するプロンプトが表示されるので、
ここでは`test-sam-project`としています。

```
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Data processing
        3 - Hello World Example with Powertools for AWS Lambda
        4 - Multi-step workflow
        5 - Scheduled task
        6 - Standalone function
        7 - Serverless API
        8 - Infrastructure event management
        9 - Lambda Response Streaming
        10 - Serverless Connector Hello World Example
        11 - Multi-step workflow with Connectors
        12 - GraphQLApi Hello World Example
        13 - Full Stack
        14 - Lambda EFS example
        15 - DynamoDB Example
        16 - Machine Learning
Template: 1

Use the most popular runtime and package type? (Python and zip) [y/N]:

Which runtime would you like to use?
        1 - aot.dotnet7 (provided.al2)
        2 - dotnet8
        3 - dotnet6
        4 - go (provided.al2)
        5 - go (provided.al2023)
        6 - graalvm.java11 (provided.al2)
        7 - graalvm.java17 (provided.al2)
        8 - java21
        9 - java17
        10 - java11
        11 - java8.al2
        12 - nodejs20.x
        13 - nodejs18.x
        14 - nodejs16.x
        15 - python3.9
        16 - python3.8
        17 - python3.12
        18 - python3.11
        19 - python3.10
        20 - ruby3.3
        21 - ruby3.2
        22 - rust (provided.al2)
        23 - rust (provided.al2023)
Runtime: 17  

What package type would you like to use?
        1 - Zip
        2 - Image
Package type: 1

Based on your selections, the only dependency manager available is pip.
We will proceed copying the template using pip.

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: n

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: y
AppInsights monitoring may incur additional cost. View https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/appinsights-what-is.html#appinsights-pricing for more details

Would you like to set Structured Logging in JSON format on your Lambda functions?  [y/N]: n

Project name [sam-app]: test-sam-project
```

</details>


作成されたディレクトリに移動します。
```
cd test-sam-project
```

作成されたディレクトリのフォルダ構造は次のようになっています。

```
root
│  .gitignore
│  README.md
│  samconfig.toml
│  template.yaml
│  __init__.py
│
├─events
│      event.json
│
├─hello_world
│      app.py
│      requirements.txt
│      __init__.py
│
└─tests
    │  requirements.txt
    │  __init__.py
    │
    ├─integration
    │      test_api_gateway.py
    │      __init__.py
    │
    └─unit
            test_handler.py
            __init__.py
```

# Lambda関数のソース
`hello_world`ディレクトリにある`app.py`ファイルに Lambda関数のソースが記載されてるので、今回は下記のように編集します。

```python:app.py
import json

def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))
    return {
        'statusCode': 200,
        'body': json.dumps('Hello Lambda!')
    }
```

Lambda関数の設定は`template.yaml`ファイルに設定してあります。
必要に応じて編集してください。今回はデフォルトのまま使用します。

# ローカルでLambda関数を実行してみる
Docker Desktopを起動し、SAM CLI を使用してローカルでLambda関数を実行します。

```cli
sam local invoke HelloWorldFunction --event events/event.json
```

下記のように`lambda_handler`関数で定義していた内容が、ログ出力される事が確認できました。
```
～～～
{"statusCode": 200, "body": "\"Hello Lambda!\""}
```

# ローカルAPIを起動する

次のコマンドでローカル環境でAPIを起動してみます。
次のコマンドを実行するとURLが出力されます。

```cli
sam local start-api
```

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-start-api.html


今回は`template.yaml`において下記のようにエンドポイントのパスを記載しています。
このエンドポイントに対してGETリクエストを送ってみます。

```
~~~
Properties:
  Path: /hello
  Method: get
~~~
```

PostmanでGETリクエストを送ってみたところ`Hello Lambda!`が返ってきていることを確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/2faa1346-78b5-9be3-b959-ed2d331eacad.png)