AWS SAM：API Gateway + Lambda + DynamoDB の基本構成を作ってみた

## はじめに

AWS SAM（Serverless Application Model）は、サーバーレスアプリケーションの構築・ローカルテスト・デプロイをシンプルにしてくれる便利なフレームワークです。

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

この記事では、API Gateway からリクエストを送信し、Lambda 関数（Python）を経由して DynamoDB のテストデータを取得し、レスポンスとして返すシンプルな構成を試してみた記録をまとめます。

## 書こうと思ったきっかけ

以前から SAM に強い関心があり、実際に手を動かして検証してみたいと思っていました。前回の記事では、シンプルな Hello World チュートリアルを実施した内容をまとめていますので、興味のある方はぜひ参考にしてみてください。

**結構、簡単で驚いた。（SAMすごい！！）**

https://qiita.com/free-honda/items/d7af39a4f8c9d545450a

サーバーレス構成やデプロイフローの理解を深めたかったこともあり、簡単な検証の記録として残していきます。

**※内容に不備などがございましたら、お手数ですが優しくご指摘いただけますと幸いです。**

## 実際にやってみた

### 簡単な検証内容

API 経由で DynamoDB に保存されたテストデータを取得し、Lambda からレスポンスとして返す。

構成は以下のようになります：

```
[API Gateway] → [Lambda] → [DynamoDB]
```

**こんな感じの簡単な構成**

![Screenshot 2025-06-07 at 16.08.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/39aa0b4b-5db5-40cc-8bf1-7213cf8389e4.png)

引用画像：https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/http-api-dynamo-db.html

### ディレクトリ構成

```
sam-dynamodb-example/
├── template.yaml               # インフラ構成を定義する SAM テンプレート
├── samconfig.toml              # sam deploy --guided の設定内容（初回デプロイ後に生成）
├── hello_world/
│   ├── app.py                 # Lambda 関数本体（Python）
│   └── __init__.py           # 空で OK（パッケージとして認識させるため）
```

**こんな感じのディレクトリ構成で検証してみました**

![Screenshot 2025-06-07 at 16.40.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/2ba1d9bf-e645-4ac0-969f-068833830c9e.png)

## ■ 前提条件

以下のツールがインストール済みであること：

* AWS CLI（aws configure）

* AWS SAM CLI（sam --version）

**AWS CLIやSAMの設定がまだの方は、参考にしてみてください！**

https://qiita.com/free-honda/items/866986d98fdb2fc1a56e

https://qiita.com/free-honda/items/d7af39a4f8c9d545450a

## 必要な構成（AWS SAM）

以下の2つの主要ファイルと1つのリソース定義で構築できます。

### template.yaml

DynamoDB テーブル、Lambda 関数、API Gateway エンドポイントの 3 つを定義しています。

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM + Lambda + API Gateway + DynamoDB

Resources:
  ItemsTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ItemsTable
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      KeySchema:
        - AttributeName: id
          KeyType: HASH
      BillingMode: PAY_PER_REQUEST

  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.12
      Environment:
        Variables:
          TABLE_NAME: !Ref ItemsTable
      Policies:
        - DynamoDBReadPolicy:
            TableName: !Ref ItemsTable
      Events:
        HelloWorldApi:
          Type: Api
          Properties:
            Path: /hello
            Method: get
```

### hello\_world/app.py

DynamoDB から ID が "test" のデータを取得し、JSON 形式で返します。

```python
import os
import boto3
import json

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ['TABLE_NAME'])

def lambda_handler(event, context):
    # テスト用のid = "test" のデータを取得
    try:
        response = table.get_item(Key={'id': 'test'})
        item = response.get('Item', {})
    except Exception as e:
        return {
            "statusCode": 500,
            "body": json.dumps({"error": str(e)})
        }

    return {
        "statusCode": 200,
        "body": json.dumps(item)
    }
```

## AWS 環境にデプロイする手順

### 1. 初回デプロイ（対話形式で設定）

```bash
sam deploy --guided
```

例）対話での入力内容：

```
Stack Name: sam-dynamodb-example
AWS Region: ap-northeast-1
Confirm changes before deploy: n
Allow SAM CLI IAM role creation: y
Disable rollback: n
HelloWorldFunction may not have authorization defined, Is this okay? y
Save arguments to configuration file: y
SAM configuration file: samconfig.toml
SAM configuration environment: default
```

**実際のターミナル画面**

![Screenshot 2025-06-07 at 16.13.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/906acfaa-0e27-4f08-a028-54fab5aebaad.png)

### 2. テストデータの投入（デプロイ後に実施）

```bash
aws dynamodb put-item \
  --table-name ItemsTable \
  --item '{"id": {"S": "test"}, "message": {"S": "Hello from DynamoDB!"}}'
```

**問題なく、テストデータが投入されていることが確認できました！**

![Screenshot 2025-06-07 at 16.18.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/8dc26f08-59ab-476b-baa4-9aeee4f0f386.png)


### 各リソース作成後の状況確認

**Lambda 関数、API Gatewayも問題なく作成されていました！**

![Screenshot 2025-06-07 at 16.15.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/08a7d32b-131a-4bac-ad2d-8a310f9e4b9c.png)

**DynamoDB テーブルも問題なく作成されていました！**

![Screenshot 2025-06-07 at 16.15.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/2faaa611-4afb-4980-8933-1cea83f13e80.png)

### 3. デプロイ後に表示されるエンドポイントにアクセスして確認

API Gateway の URL は毎回探すのが大変で、つい迷子になってしまいがちですが、以下の画像の赤枠部分に表示されていますので、参考にしてみてください。

今回の例では、この URL の末尾に `/hello` を付けて、ブラウザからアクセスする形になります。

![Screenshot 2025-06-07 at 16.31.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/c5802382-ba2e-432d-b5dd-c593703b2822.png)


```bash
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello
```

テストデータの取得が問題なくできたため、今回の検証は成功です！

![Screenshot 2025-06-07 at 16.20.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/a5a6f216-964d-4cbc-867a-feb167985f95.png)

## まとめ

ここまで読んでいただき、ありがとうございました！

:::note info
**AWS SAM を使うことで、API Gateway + Lambda + DynamoDB の基本構成がとても簡単に試せることがわかりました。**
:::

次のステップでは、POST リクエストによるデータ登録や、複数件の取得、さらには Cognito や IAM による認証の追加などにも取り組んでみたいと思います！（SAMめちゃくちゃ便利...）

## おまけ：アプリケーションを削除

以下のコマンドで削除できますので、不要になったタイミングで削除しておくことをおすすめします。

```bash
aws cloudformation delete-stack --stack-name sam-app
```

**こちらもいい感じに削除されました！**

![Screenshot 2025-06-07 at 16.44.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/5558d829-2e74-411b-b938-ff64feccb0a9.png)