LocalStackを用いたS3オブジェクト登録API(API Gateway＋Lambda)作成方法 メモ

* LocalStackを用いて、S3バケットにオブジェクト登録を行うAPIをAPI Gateway + Lambdaで作成する方法についてメモする。

## LocalStack及びS3 準備

* [こちら](https://qiita.com/KWS_0901/items/f9579d9c360cf42dc97d)の手順でLocalStackとオブジェクト登録先のバケット(`sample-bucket`)を準備しておく。


## API Gateway 準備

* REST API を作成する

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

    ```shell
    aws apigateway create-rest-api --name 'LambdaS3TestAPI' --endpoint-url=http://localhost:4567 --region us-east-1 --profile localstack
    {
        "id": "A-Z2699261A-Z3",
        "name": "'LambdaS3TestAPI'",
        "createdDate": "2021-10-09T04:56:42.976000+00:00"
    }
    ```

* ルートリソースID取得

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

* 子リソース追加

  パス名：`lambda_s3_test`

  ```shell
  aws apigateway create-resource --rest-api-id A-Z2699261A-Z3 --parent-id 8955626A-Z80 --path-part lambda_s3_test --endpoint-url=http://localhost:4567 --region us-east-1 --profile localstack
  {
      "id": "5A-Z12A-Z75998",
      "parentId": "8955626A-Z80",
      "pathPart": "lambda_s3_test",
      "path": "/lambda_s3_test",
      "resourceMethods": {
          "GET": {}
      }
  }
  
  ```

* HTTPメソッド追加

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

  

## Lambda 準備

* `lambda_s3_test.py`

  S3バケット`sample-bucket`にJSONファイルをオブジェクトとして配置する。

  ```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'
  )
  
  s3 = session.resource(
      service_name='s3', 
      endpoint_url='http://localhost:4572'
  )
  
  def lambda_handler(event, context):
  
      bucket_name = 'sample-bucket'
      key = 'sample_' + datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '.json'
      body = '{"sample_key":"sample_value"}'
  
      s3.Bucket(bucket_name).put_object(Key=key, Body=body)
      
      return 's3 put JSON_FILE'
  ```

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

* アップロード

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

* 起動

  ```shell
  aws lambda invoke --cli-binary-format raw-in-base64-out --function-name sample-function result.log --endpoint-url=http://localhost:4574 --profile=localstack
  {
      "StatusCode": 200
  }
  ```

* 確認

  ```shell
  aws s3 ls s3://sample-bucket --endpoint-url=http://localhost:4572 --profile=localstack
  2021-10-09 11:25:03         29 sample_2021-10-09-02-25-03.json
  ```

  ※ファイルが配置されている。



## API Gateway - Lambda設定

* Lambda ARN確認

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

* API Gateway - Lambda設定

  ```shell
  aws apigateway put-integration --rest-api-id A-Z2699261A-Z3 --resource-id 5A-Z12A-Z75998 --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:sample-function/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:sample-function/invocations",
      "integrationResponses": {
          "200": {
              "statusCode": 200,
              "responseTemplates": {
                  "application/json": null
              }
          }
      }
  }
  ```

* 設定デプロイ

  ```shell
  aws apigateway create-deployment --rest-api-id A-Z2699261A-Z3 --stage-name test --endpoint-url=http://localhost:4567 --region us-east-1 --profile localstack
  {
      "id": "6271136713",
      "description": "",
      "createdDate": "2021-10-09T05:08:40.688000+00:00"
  }
  ```

  

## 動作確認

* APIリクエスト

パス:`/restapis/${REST_API_ID}/test/_user_request_/${登録したAPIパス名}`

```http
POST /restapis/A-Z2699261A-Z3/test/_user_request_/lambda_s3_test HTTP/1.1
Host: localhost:4567
Content-Type: application/json
Content-Length: 2

{}
```

* APIレスポンス

```
"s3 put JSON_FILE"
```



* S3オブジェクト確認

```shell
aws s3 ls s3://sample-bucket --endpoint-url=http://localhost:4572 --profile=localstack
2021-10-09 11:25:03         29 sample_2021-10-09-02-25-03.json
2021-10-09 13:43:27         29 sample_2021-10-09-04-43-27.json
2021-10-09 14:14:53         29 sample_2021-10-09-05-14-53.json
```

※オブジェクトが追加されている。

## 参考情報

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