LocalStack とSAM CLIを用いたローカルLambda +DynamoDB API 作成方法メモ

* LocalStackとSAM CLIを用いたローカルLambda + DynamoDB APIの作成方法についてメモする。
* POSTメソッドでリクエストボディに指定した値をDynamoDBテーブル検索して返却する。

## 構成

![sam+dynamo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/5c881d46-febb-81c6-196c-36d81970d5d9.png)




## LocalStack 準備

* [こちら](https://qiita.com/KWS_0901/items/f9579d9c360cf42dc97d)の手順でDocker LocalStack環境を準備しておく。

## Dynamo DB 準備

* テーブル(`sample-table`)作成

  ```shell
  aws dynamodb create-table --table-name sample-table --attribute-definitions AttributeName=Data,AttributeType=S --key-schema AttributeName=Data,KeyType=HASH --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 --endpoint-url=http://localhost:4566 --profile localstack
  
  {
      "TableDescription": {
          "AttributeDefinitions": [
              {
                  "AttributeName": "Data",
                  "AttributeType": "S"
              }
          ],
          "TableName": "sample-table",
          "KeySchema": [
              {
                  "AttributeName": "Data",
                  "KeyType": "HASH"
              }
          ],
          "TableStatus": "ACTIVE",
          "CreationDateTime": "2021-10-09T14:55:59.763000+09:00",
          "ProvisionedThroughput": {
              "LastIncreaseDateTime": "1970-01-01T09:00:00+09:00",
              "LastDecreaseDateTime": "1970-01-01T09:00:00+09:00",
              "NumberOfDecreasesToday": 0,
              "ReadCapacityUnits": 1,
              "WriteCapacityUnits": 1
          },
          "TableSizeBytes": 0,
          "ItemCount": 0,
          "TableArn": "arn:aws:dynamodb:ddblocal:000000000000:table/sample-table"
      }
  }
  ```

* 動作確認(データ登録)

  ```shell
  aws dynamodb put-item --table-name sample-table --item={\"Data\":{\"S\":\"fuga\"}}  --endpoint-url=http://localhost:4566 --profile localstack
  ```

  * 登録データ確認

    ```shell
    aws dynamodb scan --table-name sample-table --endpoint-url=http://localhost:4566 --profile localstack
    {
        "Items": [
            {
                "Data": {
                    "S": "fuga"
                }
            }
        ],
        "Count": 1,
        "ScannedCount": 1,
        "ConsumedCapacity": null
    }
    ```

    

## Lambda準備

### Lambda

* ひな形作成

  ```shell
  sam init
  ```

  ※ランタイムはPython3.8を選択。

* `template.yml`

  * Hello World Exampleを利用する。

  * Pathを`/search_data`に変更する。

  * POSTメソッドを受け付けるように`Method`を`post`に変更する。

    ```yaml
    ...
    	Events:
            HelloWorld:
              Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
              Properties:
                Path: /search_data
                Method: post
    ...
    ```

    

* `requrements.txt`

  ```
  requests
  boto3
  ```

  ※DynamoDBアクセス用にboto3追加

  

* Lambda処理(`app.py`)修正

  ```python
  import json
  from boto3.session import Session
  
  # DynamoDB接続設定
  session = Session(aws_access_key_id='dummy',
      aws_secret_access_key='dummy',
      region_name='ap-northeast-1'
  )
  dynamodb = session.resource(
      service_name='dynamodb', 
      endpoint_url='http://localstack:4566'
  )
  table= dynamodb.Table('sample-table')
  
  
  def lambda_handler(event, context):
      req_body = json.loads(event["body"])
      primary_key = {"Data": req_body['data']}
      res = table.get_item(Key=primary_key)
      item = res["Item"]  
      print(item,type(item))
      return {
          "statusCode": 200,
          "body": json.dumps(item),
      }
  
  ```



## 動作確認

* ビルド

  ```
  sam build
  ```

* 実行

  ```
  sam local start-api --docker-network docker.internal
  ```

* リクエスト

  ```http
POST /search_data HTTP/1.1
Host: localhost:3000
Content-Type: application/json
Content-Length: 23

{
    "data":"fuga"
}
  ```

* レスポンス

  ```json
{
    "Data": "fuga"
}
  ```

  

## 参考情報

* [Architecting and Building - レガシーシステムにサーバーレスを利用して素早くサービスを追加するには【後半】](https://logmi.jp/business/articles/323350)