どこにでもいる30代SEの学習ブログ

主にプログラミング関連の学習内容。読んだ本の感想や株式投資についても書いてます。

【AWS】HTTP API+Lambda+DynamoDBのチュートリアルをやってみた

API Gatewayチュートリアルの中に「Lambda と DynamoDB を使用した CRUD API の構築」があったのでやってみました。HTTP APIを使用するチュートリアルです。

docs.aws.amazon.com

[1] DynamoDBテーブルの作成

idをプライマリキーに持つテーブルを作成します。

f:id:predora005:20210411160705p:plain

[2] Lambda関数の作成

チュートリアルは「Node.js」ですが、私は「Python」で作成しました。

f:id:predora005:20210411161204p:plain

DynamoDBへのアクセス権限を設定します。ポリシーテンプレートから「シンプルなマイクロサービスのアクセス権限」を選択します。

f:id:predora005:20210411161209p:plain

関数の作成後、チュートリアルソースコードPython用に変更します。

import json
import boto3
from decimal import Decimal

# DynamoDBのテーブルにアクセス
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('http-crud-tutorial-items')

# Decimal型をJSONに変換するための関数
def json_serialize(obj):
    if isinstance(obj, Decimal):
        return float(obj)
    raise TypeError

# Lambda関数のエントリーポイント
def lambda_handler(event, context):
    
    statusCode = 200
    headers = { 'Content-Type': 'application/json' }
    try:
        routeKey = event['routeKey']
        if routeKey == 'DELETE /items/{id}':
            id = event['pathParameters']['id']
            table.delete_item(Key={'id': id})
            body = f"Deleted item {id}"
            
        elif routeKey == 'GET /items/{id}':
            id = event['pathParameters']['id']
            body = table.get_item(Key={'id': id})
        
        elif routeKey == 'GET /items':
            body = table.scan()
        
        elif routeKey == 'PUT /items':
            request = json.loads(event['body'])
            table.put_item(Item={
                'id': request['id'],
                'price': request['price'],
                'name': request['name']
            })
            body = f"Put item {request['id']}"
            
        else:
            raise ValueError(f"Unsupported route: {routeKey}")
        
    except Exception as err:
        statusCode = 400
        body = err
    
    finally:
        body = json.dumps(body, default=json_serialize)

    return {
        'statusCode': statusCode,
        'body': body,
        'headers': headers
    }

「Decimal型をJSONに変換するための関数」は以下の記事を参考にさせていただきました。

python3 で Decimal を JSON に変換 - Qiita

[3] HTTP APIを作成

APIタイプから「HTTP API」を選択します。

f:id:predora005:20210411162406p:plain

統合から「Lambda」を選択し、Lambda関数は先ほど作成した関数の名称を入力します。

f:id:predora005:20210411162412p:plain

ルートは以下の4つを設定します。

  • "GET /items/{id}":1つの項目を取得
  • "GET /items":すべての項目を取得
  • "DELETE /items/{id}":1つの項目を削除
  • "PUT /items":1つの項目を追加

f:id:predora005:20210411162419p:plain

ステージはデフォルトのままとします。

f:id:predora005:20210411162424p:plain

APIの作成後に表示されるURLは、APIを実際に使うときに使用します。

f:id:predora005:20210411163439p:plain

[4] APIをテスト

[4-1] 項目を追加(PUT)

次のコマンドを実行します。[APIのURL]は自身が作成APIのURLに置き換えます。

curl -v -X "PUT" -H "Content-Type: application/json" -d ¥
"{\"id\": \"abcdef234\", \"price\": 12345, \"name\": \"myitem\"}" ¥
[APIのURL]/items

コマンド実行に成功すると、以下のような応答が返ってきます。

* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
* We are completely uploaded and fine
< HTTP/2 200 
< date: Sun, 11 Apr 2021 07:36:31 GMT
< content-type: application/json
< content-length: 20
< apigw-requestid: dm8H5jP6NjMEJ5g=
< 
* Connection #0 to host [APIのURL] left intact
"Put item abcdef234"* Closing connection 0

[4-2] すべての項目を取得(GET)

次のコマンドを実行します。

curl -v [APIのURL]/items

コマンド実行に成功すると、以下のような応答が返ってきます。

* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200 
< date: Sun, 11 Apr 2021 07:40:48 GMT
< content-type: application/json
< content-length: 515
< apigw-requestid: dm8wCh7itjMEP1w=
< 
* Connection #0 to host [APIのURL] left intact
{"Items": [{"price": 12345.0, "id": "abcdef234", "name": "myitem"}], 
"Count": 1, "ScannedCount": 1, 
"ResponseMetadata": {"RequestId": "VB23I48FNE4DLDH2F86H9IRHDVVV4KQNSO5AEMVJF66Q9ASUAAJG", 
"HTTPStatusCode": 200, 
"HTTPHeaders": {"server": "Server", "date": "Sun, 11 Apr 2021 07:40:48 GMT", 
"content-type": "application/x-amz-json-1.0", "content-length": "107", 
"connection": "keep-alive", 
"x-amzn-requestid": "VB23I48FNE4DLDH2F86H9IRHDVVV4KQNSO5AEMVJF66Q9ASUAAJG", 
"x-amz-crc32": "1550053751"}, "RetryAttempts": 0}}* Closing connection 0

[4-3] 1つの項目を取得(GET)

次のコマンドを実行します。

curl -v [APIのURL]/items/abcdef234

コマンド実行に成功すると、すべての項目を取得したときと似たような結果が返ってきます。

[4-4] 1つの項目を削除(DELETE)

次のコマンドを実行します。

curl -v -X "DELETE" [APIのURL]/items/abcdef234

コマンド実行に成功すると、以下のような応答が返ってきます。

* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200 
< date: Sun, 11 Apr 2021 07:45:54 GMT
< content-type: application/json
< content-length: 24
< apigw-requestid: dm9f8iGMNjMEPbA=
< 
* Connection #0 to [APIのURL] left intact
"Deleted item abcdef234"* Closing connection 0

[5] リソースの削除

以下のリソースを削除したら終了です。

  • DynamoDBテーブル
  • HTTP API
  • Lambda関数
  • Lambda関数のロググループ
  • Lambda関数の実行ロール

終わりに

Node.jsをPythonに置き換えるところは時間がかかりましたが、それ以外はスムーズに行うことができました。今回は、curlコマンドでAPIにアクセスしたため、煩雑に感じました。ですが、ブラウザなどからUI経由でアクセスできるようにすれば、非常にお手軽で便利だなと思います。

出典