LocalStackを用いたAPI Gateway＋Lambda+DynamoDB API作成方法 メモ

* LocalStackを用いて、DynamoDBにデータ登録を行うAPIをAPI Gateway + Lambdaで作成する方法についてメモする。

## 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:4569 --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:4569 --profile localstack
  ```

  * 登録データ確認

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

    

## API Gateway 準備

* REST API を作成する

  * リソースID(`id`)を控える

    ```shell
    aws apigateway create-rest-api --name 'LambdaDynamoDBTestAPI' --endpoint-url=http://localhost:4567 --region us-east-1 --profile localstack
    {
        "id": "0157166521",
        "name": "'LambdaDynamoDBTestAPI'",
        "createdDate": "2021-10-09T06:01:05.462000+00:00"
    }
    ```

* ルートリソースID(以下`id`)取得

  ```shell
  aws apigateway get-resources --rest-api-id 0157166521 --endpoint-url=http://localhost:4567 --region us-east-1 --profile localstack
  {
      "items": [
          {
              "id": "4739445932",
              "path": "/",
              "resourceMethods": {
                  "GET": {}
              }
          }
      ]
  }
  ```

* 子リソース追加

  パス名：`lambda_dynamodb_test`

  リソースID(以下`id`)を控える。

  ```shell
  aws apigateway create-resource --rest-api-id 0157166521 --parent-id 4739445932 --path-part lambda_dynamodb_test --endpoint-url=http://localhost:4567 --region us-east-1 --profile localstack
  {
      "id": "A-Z13318A-Z712",
      "parentId": "4739445932",
      "pathPart": "lambda_dynamodb_test",
      "path": "/lambda_dynamodb_test",
      "resourceMethods": {
          "GET": {}
      }
  }
  ```

* HTTP POSTメソッド追加

  ```shell
  aws apigateway put-method --rest-api-id 0157166521 --resource-id A-Z13318A-Z712 --http-method POST --authorization-type "NONE" --endpoint-url=http://localhost:4567 --region us-east-1 --profile localstack
  {
      "httpMethod": "POST",
      "authorizationType": "NONE"
  }
  ```

  

## Lambda 準備

* `lambda_dynamodb_put_test.py`

  DynamoDBテーブル`sample-table`にデータを登録する。

  ```python
  import boto3
  from boto3.session import Session
  from datetime import datetime 
  
  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://localhost:4569'
  )
  
  def lambda_handler(event, context):
      table = dynamodb.Table('sample-table')
      data = 'sample_' + datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
      response = table.put_item(
         Item={
              'Data': data
          }
      )
      return response
  ```

* 上記ファイルを`lambda_dynamodb_put_test.zip`にzip化する。

* アップロード

  ```shell
  aws lambda create-function --function-name="lambda-dynamodb-put" --runtime=python3.8 --role="arn:aws:iam::123456789012:role/service-role/lambda-sample-role" --handler=lambda_dynamodb_put_test.lambda_handler --zip-file fileb://lambda_dynamodb_put_test.zip --endpoint-url=http://localhost:4574 --profile=localstack
  ```

* 起動

  ```shell
aws lambda invoke --cli-binary-format raw-in-base64-out --function-name lambda-dynamodb-put result.log --endpoint-url=http://localhost:4574 --profile=localstack

{"StatusCode": 200}
  ```

* 動作確認

  ```shell
aws dynamodb scan --table-name sample-table --endpoint-url=http://localhost:4569 --profile localstack

{
    "Items": [
        {
            "Data": {
                "S": "fuga"
            }
        },
        {
            "Data": {
                "S": "sample_2021-10-09-06-38-16"
            }
        }
    ],
    "Count": 2,
    "ScannedCount": 2,
    "ConsumedCapacity": null
}
  ```

  ※データが追加されている。



## API Gateway - Lambda 設定

* Lambda ARN確認

  ```shell
  aws lambda list-functions --endpoint-url=http://localhost:4574 --profile=localstack{    "Functions": [        {            "FunctionName": "lambda-dynamodb-put",            "FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:lambda-dynamodb-put",            "Runtime": "python3.8",            "Handler": "lambda_dynamodb_put_test.lambda_handler",            "Timeout": 60,            "Version": "$LATEST"        }    ]}
  ```

* API Gateway - Lambda設定

  ```shell
  aws apigateway put-integration --rest-api-id 0157166521 --resource-id A-Z13318A-Z712 --http-method POST --type AWS_PROXY --integration-http-method POST --uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:lambda-dynamodb-put/invocations --passthrough-behavior WHEN_NO_MATCH --endpoint-url=http://localhost:4567 --region us-east-1 --profile localstack {    "type": "AWS_PROXY",    "httpMethod": "POST",    "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:lambda-dynamodb-put/invocations",    "integrationResponses": {        "200": {            "statusCode": 200,            "responseTemplates": {                "application/json": null            }        }    }}
  ```

* 設定デプロイ

  ```shell
  aws apigateway create-deployment --rest-api-id 0157166521 --stage-name test --endpoint-url=http://localhost:4567 --region us-east-1 --profile localstack{    "id": "1850348379",    "description": "",    "createdDate": "2021-10-09T06:43:04.032000+00:00"}
  ```

  

## 動作確認

* APIリクエスト

```http
POST /restapis/0157166521/test/_user_request_/lambda_dynamodb_test HTTP/1.1
Host: localhost:4567
Content-Type: application/json
Content-Length: 2

{}
```

* APIレスポンス

```
{"ResponseMetadata": {"RetryAttempts": 0, "HTTPStatusCode": 200, "RequestId": "9f2c5ca3-6187-4d92-811d-5cd62c5f5289", "HTTPHeaders": {"x-amzn-requestid": "9f2c5ca3-6187-4d92-811d-5cd62c5f5289", "content-length": "2", "access-control-allow-methods": "HEAD,GET,PUT,POST,DELETE,OPTIONS,PATCH", "server": "BaseHTTP/0.3 Python/2.7.13, Jetty(8.1.12.v20130726)", "x-amz-crc32": "2745614147", "date": "Sat, 09 Oct 2021 06:44:22 GMT", "access-control-allow-origin": "*", "access-control-allow-headers": "authorization,content-type,content-md5,x-amz-content-sha256,x-amz-date,x-amz-security-token,x-amz-user-agent", "content-type": "application/x-amz-json-1.0"}}}
```

* DynamoDB登録データ確認

```shell
aws dynamodb scan --table-name sample-table --endpoint-url=http://localhost:4569 --profile localstack

{
    "Items": [
        {
            "Data": {
                "S": "fuga"
            }
        },
        {
            "Data": {
                "S": "sample_2021-10-09-06-38-16"
            }
        },
        {
            "Data": {
                "S": "sample_2021-10-09-06-44-22"
            }
        }
    ],
    "Count": 3,
    "ScannedCount": 3,
    "ConsumedCapacity": null
}
```

※データが追加されている。

## 参考情報

* [LocalStack入門(第５回)　ブラウザからのAPI Gateway,Lambda関数アクセス方法](https://enjoy-analysis.com/apigateway/)

* [ステップ 3: Python で項目を作成、読み込み、更新、削除する](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/GettingStarted.Python.03.html)