Web API(API Gateway(HTTP API)+Lambda)の仕組みでDynamoDBを操作する仕組みを作ってみた。
やること
適当なWindows端末からcurlコマンドを打ち、API Gateway(HTTP API)からバックエンドのLambda(Python)、DynamoDBに接続し操作する。
※curlコマンドは事前にインストールしておくこと
構成
実践!
1.IAMポリシー作成
1-1.[IAM]-[ポリシー]-[ポリシー作成]
1-2.JSONに下記を入力
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1428341300017", "Action": [ "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": "*" }, { "Sid": "", "Resource": "*", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow" } ] }
1-3.確認して作成画面が表示されたら下記を入力
・ポリシー名:lambda-dynamo-policy
・説明:空白
1-4.[ポリシーの作成]をクリック
2.ロール作成
2-1.[IAM]-[ロール]-[ロールを作成]
2-2.信頼されたエンティティを選択が表示されたら下記を入力
・信頼されたエンティティタイプ:AWSのサービス
・ユースケース:Lambda
2-3.[次へ]をクリック
2-4.許可を追加が表示されたら[lambda-dynamo-policy]を選択
2-5.[次へ]をクリック
2-6.ロール名は[lambda-dynamo-role]を入力し、[ロールを作成]をクリック
3.DynamoDBテーブル作成
3-1.[DynamoDB]-[テーブル]-[テーブルの作成]
3-2.テーブルの作成画面が表示されたら下記を入力
・テーブル名:sample-dynamodb
・パーティションキー:id
3-3.[テーブルの作成]をクリック
4.DynamoDB項目作成
4-1.[DynamoDB]-[テーブル]-[sample-dynamodb]
4-2.[アクション]-[項目を作成]
4-3.下記を入力
・id:123
・value:test
※[新しい属性の追加]-[文字列]で追加して入力する
5.Lambda関数作成
5-1.[Lambda]-[関数]-[関数の作成]
5-2.関数の作成画面が表示されたら下記を入力
・一から作成:✅
・関数名:sample-function
・ランタイム:Python3.10
・実行ロール:既存のロールを使用する
・既存のロール:lambda-dynamo-role
5-3.[関数の作成]をクリック
5-4.コードに下記を入力
※POSTやPUT、DELETEもあるが今回はGETのみ使用
import json import boto3 dynamodb = boto3.client('dynamodb') table_name = 'sample-dynamodb' def lambda_handler(event, context): method = event["routeKey"] if "PUT" in method: return create(event, context) elif "GET" in method: return read(event, context) elif "DELETE" in method: return delete(event, context) else: return { "statusCode": 400, "body": json.dumps({"error": "Unsupported method"}) } def create(event, context): id = event["pathParameters"]["id"] value = event["pathParameters"]["value"] options = { 'TableName': table_name, 'Item': { 'id': {'S': id}, 'value': {'S': value}, } } response = dynamodb.put_item(**options) res = response["ResponseMetadata"]["HTTPStatusCode"] if res == 200: return { "statusCode": 200, "body": json.dumps(response) } else: return { "statusCode": 404, "body": json.dumps({"error": "Item not found"}) } def read(event, context): id = event["pathParameters"]["id"] options = { 'TableName': table_name, 'Key': { 'id': {'S': id}, } } response = dynamodb.get_item(**options) if 'Item' in response: return { "statusCode": 200, "body": json.dumps(response) } else: return { "statusCode": 404, "body": json.dumps({"error": "Item not found"}) } def delete(event, context): id = event["pathParameters"]["id"] options = { 'TableName': table_name, 'Key': { 'id': {'S': id}, } } response = dynamodb.delete_item(**options) res = response["ResponseMetadata"]["HTTPStatusCode"] if res == 200: return { "statusCode": 200, "body": json.dumps(response) } else: return { "statusCode": 404, "body": json.dumps({"error": "Item not found"}) }
6.Lambdaテスト
6-1.作成したLambda関数を選択し、[Test]をクリック
6-2.テストイベントを設定が表示されたら下記を入力
・新しいイベントを作成:✅
・イベント名:MyEvent
・イベントJSON:下記を入力
{ "routeKey": "GET /items/123/", "pathParameters": { "id": "123", "value": "test1" } }
6-3.[Test]をクリック
6-4.下記のような返答が返ってくることを確認
Test Event Name GET Response { "statusCode": 200, "body": "{\"Item\": {\"id\": {\"S\": \"123\"}, \"value\": {\"S\": \"test\"}}, \"ResponseMetadata\": {\"RequestId\": \"0IPTDQ3K2C66RCCFCM75DKM5RRVV4KQNSO5AEMVJF66Q9ASUAAJG\", \"HTTPStatusCode\": 200, \"HTTPHeaders\": {\"server\": \"Server\", \"date\": \"Mon, 08 May 2023 10:44:17 GMT\", \"content-type\": \"application/x-amz-json-1.0\", \"content-length\": \"48\", \"connection\": \"keep-alive\", \"x-amzn-requestid\": \"0IPTDQ3K2C66RCCFCM75DKM5RRVV4KQNSO5AEMVJF66Q9ASUAAJG\", \"x-amz-crc32\": \"2920716868\"}, \"RetryAttempts\": 0}}" }
7.API Gateway作成
7-1.[API Gateway]-[HTTP API]内の[構築]をクリック
7-2.APIの作成が表示されたら下記を入力
・API名:SampleAPI
7-3.[次へ]をクリック
7-4.ルートを設定が表示されたら、なにもせず[次へ]
7-5.ステージを定義が表示されたら[ステージを追加]を選択し、ステージ名に[staging]を入力
7-6.[次へ]をクリック
7-7.確認して作成が表示されたら[作成]をクリック
7-8.左ペインから[Routes]を選択
7-9.[Create]をクリック
7-10.下記のようなツリー構造を作成
/items(ルート)
└ GET(メソッド)
/{id}(ルート)
└ GET(メソッド)
└ DELETE(メソッド)
/{value}(ルート)
└ PUT(メソッド)
7-11.作成したメソッドをクリックし、右にルートの詳細が表示されたら[統合をアタッチする]をクリック
7-12.プルダウンで[sample-function]を選択し、[統合をアタッチする]をクリック
7-13.[デプロイ]をクリック
7-14.デプロイを作成してステージへアタッチが表示されたら、下記を入力
・ステージを選択:staging
・この出プロの変更について説明:空白
7-15.[ステージへデプロイ]
8.API Gateway動作確認
8-1.下記curlコマンドを実行する
・GET
>curl -X GET https://wobmkjeu87.execute-api.ap-northeast-1.amazonaws.com/staging/items/123 {"Item": {"id": {"S": "123"}, "value": {"S": "test"}}, "ResponseMetadata": {"RequestId": "1Q62TFT1T9QU5N6L7BKK4PQVT3VV4KQNSO5AEMVJF66Q9ASUAAJG", "HTTPStatusCode": 200, "HTTPHeaders": {"server": "Server", "date": "Mon, 08 May 2023 10:35:59 GMT", "content-type": "application/x-amz-json-1.0", "content-length": "48", "connection": "keep-alive", "x-amzn-requestid": "1Q62TFT1T9QU5N6L7BKK4PQVT3VV4KQNSO5AEMVJF66Q9ASUAAJG", "x-amz-crc32": "2920716868"}, "RetryAttempts": 0}}
・CREATE
>curl -X PUT https://wobmkjeu87.execute-api.ap-northeast-1.amazonaws.com/staging/items/1234/test1 {"ResponseMetadata": {"RequestId": "T04KFSJI67NP0TDTA6NH94C0TBVV4KQNSO5AEMVJF66Q9ASUAAJG", "HTTPStatusCode": 200, "HTTPHeaders": {"server": "Server", "date": "Mon, 08 May 2023 10:36:11 GMT", "content-type": "application/x-amz-json-1.0", "content-length": "2", "connection": "keep-alive", "x-amzn-requestid": "T04KFSJI67NP0TDTA6NH94C0TBVV4KQNSO5AEMVJF66Q9ASUAAJG", "x-amz-crc32": "2745614147"}, "RetryAttempts": 0}}
・DELETE
>curl -X DELETE https://wobmkjeu87.execute-api.ap-northeast-1.amazonaws.com/staging/items/1234/test1 {"ResponseMetadata": {"RequestId": "MI42GUC3BSDJER8B4O9JEN5S7JVV4KQNSO5AEMVJF66Q9ASUAAJG", "HTTPStatusCode": 200, "HTTPHeaders": {"server": "Server", "date": "Mon, 08 May 2023 10:37:27 GMT", "content-type": "application/x-amz-json-1.0", "content-length": "2", "connection": "keep-alive", "x-amzn-requestid": "MI42GUC3BSDJER8B4O9JEN5S7JVV4KQNSO5AEMVJF66Q9ASUAAJG", "x-amz-crc32": "2745614147"}, "RetryAttempts": 0}}
感想
API GatewayのHTTP APIを使用すればブラウザのURLからPOSTなどのGET以外のメソッドを送信できると思っていたがREST APIと同じでダメでした。
やっぱりWeb APIってのはなにかしらのアプリと絡めて使う感じなんですね。( ´_ゝ`)ふーん