DynamoDBをAPIGatewayから叩く
Refs
API Gateway、Lambda、および DynamoDB の統合をテストする
DynamoDB
パーティションキーのみでソートキーのないテーブルを作成
パーティションキーはsubs_name
Lambda
Pythonで作成
IAMはDynamoDBとCloudWatch Logsにアクセスできるポリシーを設定
import boto3
import json
from decimal import Decimal
# define the DynamoDB table that Lambda will connect to
tableName = 'subs_in_use_table'
# create the DynamoDB resource
dynamo = boto3.resource('dynamodb').Table(tableName)
print('Loading function')
def lambda_handler(event, context):
'''Provide an event that contains the following keys:
- operation: one of the operations in the operations dict below
- payload: a JSON object containing parameters to pass to the
operation being performed
'''
#Decimal型の場合はint型に変換
def decimal_default_proc(obj):
if isinstance(obj, Decimal):
return int(obj)
raise TypeError
# define the functions used to perform the CRUD operations
def ddb_create(x):
dynamo.put_item(**x)
return {
'statusCode': 200,
'body': json.dumps({'message': 'Item created successfully'})
}
def ddb_read(x):
response = dynamo.get_item(**x)
if 'Item' in response:
item = response['Item']
return {
'statusCode': 200,
'body': json.dumps(item,default=decimal_default_proc)
}
else:
return {
'statusCode': 404,
'body': json.dumps({'message': 'Item not found'})
}
def ddb_update(x):
dynamo.update_item(**x)
return {
'statusCode': 200,
'body': json.dumps({'message': 'Item updated successfully'})
}
def ddb_delete(x):
dynamo.delete_item(**x)
return {
'statusCode': 200,
'body': json.dumps({'message': 'Item deleted successfully'})
}
event_body = json.loads( event['body'] )
print(event_body)
operation = event_body['operation']
operations = {
'create': ddb_create,
'read': ddb_read,
'update': ddb_update,
'delete': ddb_delete,
}
if operation in operations:
return operations[operation](event_body.get('payload'))
else:
raise ValueError('Unrecognized operation "{}"'.format(operation))
API Gateway
この記事を見て、REST APIのPOSTメソッドを作成
テスト
POST=>put_item()
リクエスト本文に以下のJSONを設定してテスト実行
{"operation":"create","payload": {"Item": {"subs_name": "Netflix","cost": 1000,"period": "monthly","update_date": "2024-06-01"}}}
以下のような結果が返ってきたため、成功
POST=>get_item()
リクエスト本文に以下のJSONを設定してテスト実行
{"operation":"read","payload":{"Key":{"subs_name":"Netflix"}}}
以下のような結果が返ってきたため、成功
エラー解決
[ERROR] TypeError: Object of type Decimal is not JSON serializable
のエラーが出たため以下の記事を見て解決した
POST=>update_item()
リクエスト本文に以下のJSONを設定してテスト実行
{"operation":"update",
"payload":{
"Key":{"subs_name":"Netflix"},
"UpdateExpression":"SET cost = :cost",
"ExpressionAttributeValues":{":cost": 1490}
}
}
以下のような結果が返ってきたため、成功
DynamoDBもちゃんと更新されてる
POST=>delete_item()
リクエスト本文に以下のJSONを設定してテスト実行
{"operation":"delete","payload":{"Key":{"subs_name":"Netflix"}}}
以下のような結果が返ってきたため、成功
APIはしっかりデプロイしようね
HTTPリクエストメソッドを使い分けるように改良する
API Gateway
Postメソッドにしか対応していなかったが、
- GET
- POST
- PUT
- DELETE
を用意して使い分けるようにした。
Lambda
import logging
import boto3
import json
from decimal import Decimal
# define the DynamoDB table that Lambda will connect to
tableName = 'subs_in_use_table'
# create the DynamoDB resource
dynamo = boto3.resource('dynamodb').Table(tableName)
print('Loading function')
def lambda_handler(event, context):
'''Provide an event that contains the following keys:
- operation: one of the operations in the operations dict below
- payload: a JSON object containing parameters to pass to the
operation being performed
'''
#Decimal型の場合はint型に変換
def decimal_default_proc(obj):
if isinstance(obj, Decimal):
return int(obj)
raise TypeError
# define the functions used to perform the CRUD operations
def ddb_create(x):
dynamo.put_item(**x)
return {
'statusCode': 200,
'body': json.dumps({'message': 'Item created successfully'})
}
def ddb_read(x):
response = dynamo.get_item(**x)
if 'Item' in response:
item = response['Item']
return {
'statusCode': 200,
'body': json.dumps(item,default=decimal_default_proc)
}
else:
return {
'statusCode': 404,
'body': json.dumps({'message': 'Item not found'})
}
def ddb_update(x):
dynamo.update_item(**x)
return {
'statusCode': 200,
'body': json.dumps({'message': 'Item updated successfully'})
}
def ddb_delete(x):
dynamo.delete_item(**x)
return {
'statusCode': 200,
'body': json.dumps({'message': 'Item deleted successfully'})
}
def ddb_scan():
response = dynamo.scan()
print(response)
if 'Items' in response:
items = response['Items']
return {
'statusCode': 200,
'body': json.dumps(items,default=decimal_default_proc)
}
else:
return {
'statusCode': 404,
'body': json.dumps({'message': 'Item not found'})
}
print("Event:", event)
operations = {
'GET': ddb_scan,
'POST': {
'read': ddb_read,
'create': ddb_create
},
'PUT': {
'update': ddb_update
},
'DELETE': {
'delete': ddb_delete
}
}
httpMethod = event['httpMethod']
if httpMethod == 'GET':
return operations[httpMethod]()
else:
event_body = json.loads(event['body'])
operation = event_body['operation']
if operation in operations[httpMethod]:
return operations[httpMethod][operation](event_body.get('payload'))
else:
raise ValueError('Unrecognized operation "{}"'.format(operation))
API Gateway、Lambda、および DynamoDB の統合をテストする➁
DynamoDB
パーティションキーとソートキーの存在するテーブルを作成
パーティションキーはuserid
、ソートキーはsubs_name
Lambda
Pythonで作成
IAMはDynamoDBとCloudWatch Logsにアクセスできるポリシーを設定
import logging
import boto3
import json
from decimal import Decimal
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# define the DynamoDB table that Lambda will connect to
tableName = 'subscription_in_use_table'
# create the DynamoDB resource
dynamo = boto3.resource('dynamodb').Table(tableName)
print('Loading function')
def lambda_handler(event, context):
'''Provide an event that contains the following keys:
- operation: one of the operations in the operations dict below
- payload: a JSON object containing parameters to pass to the
operation being performed
'''
#Decimal型の場合はint型に変換
def decimal_default_proc(obj):
if isinstance(obj, Decimal):
return int(obj)
raise TypeError
# define the functions used to perform the CRUD operations
def ddb_create(x):
dynamo.put_item(**x)
return {
'statusCode': 200,
'headers': {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
},
'body': json.dumps({'message': 'Item created successfully'})
}
def ddb_read(x):
response = dynamo.get_item(**x)
if 'Item' in response:
item = response['Item']
return {
'statusCode': 200,
'headers': {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
},
'body': json.dumps(item,default=decimal_default_proc)
}
else:
return {
'statusCode': 404,
'headers': {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
},
'body': json.dumps({'message': 'Item not found'})
}
def ddb_update(x):
dynamo.update_item(**x)
return {
'statusCode': 200,
'headers': {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
},
'body': json.dumps({'message': 'Item updated successfully'})
}
def ddb_delete(x):
dynamo.delete_item(**x)
return {
'statusCode': 200,
'headers': {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
},
'body': json.dumps({'message': 'Item deleted successfully'})
}
def ddb_scan():
response = dynamo.scan()
print(response)
if 'Items' in response:
items = response['Items']
return {
'statusCode': 200,
'headers': {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
},
'body': json.dumps(items,default=decimal_default_proc)
}
else:
return {
'statusCode': 404,
'headers': {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
},
'body': json.dumps({'message': 'Item not found'})
}
print("Event:", event)
operations = {
'GET': ddb_scan,
'POST': {
'read': ddb_read,
'create': ddb_create
},
'PUT': {
'update': ddb_update
},
'DELETE': {
'delete': ddb_delete
}
}
httpMethod = event['httpMethod']
if httpMethod == 'GET':
return operations[httpMethod]()
else:
event_body = json.loads(event['body'])
operation = event_body['operation']
if operation in operations[httpMethod]:
return operations[httpMethod][operation](event_body.get('payload'))
else:
raise ValueError('Unrecognized operation "{}"'.format(operation))
API Gateway
REST APIを作成
テスト
POST=>put_item()
リクエスト本文に以下のJSONを設定してテスト実行
{"operation":"create","payload": {"Item": { "userid":"(ユーザーID)", "subs_name": "U-Next","cost": 2189,"period": "monthly","update_date": "2024-06-01"}}}
以下のような結果が返ってきたため、成功
/DynamoDBManager - POST メソッドテストの結果
リクエスト
/DynamoDBManager
レイテンシー ms
1216
ステータス
200
レスポンス本文
{"message": "Item created successfully"}
レスポンスヘッダー
{
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Origin": "*",
"X-Amzn-Trace-Id": "Root=1-66519345-e43b5b6a27257c7e1e79928f;Parent=06b460853d21af20;Sampled=0;lineage=c412f566:0"
}
POST=>get_item()
リクエスト本文に以下のJSONを設定してテスト実行
{"operation": "read", "payload": {"Key": {
"userid": "(ユーザーID)",
"subs_name": "Netflix"
}}}
以下のような結果が返ってきたため、成功
/DynamoDBManager - POST メソッドテストの結果
リクエスト
/DynamoDBManager
レイテンシー ms
1157
ステータス
200
レスポンス本文
{"subs_name": "Netflix", "cost": 1490, "period": "monthly", "userid": "(ユーザーID)", "update_date": "2024-06-01"}
GET=>scan()
実行すると以下のような結果が返ってきたため成功
/DynamoDBManager - GET メソッドテストの結果
リクエスト
/DynamoDBManager
レイテンシー ms
1184
ステータス
200
レスポンス本文
[{"subs_name": "Netflix", "cost": 990, "period": "monthly", "userid": "(ユーザーID)", "update_date": "2024-06-01"}, {"subs_name": "U-Next", "cost": 2189, "period": "monthly", "userid": "(ユーザーID)", "update_date": "2024-06-01"}, {"subs_name": "\u30e9\u30b8\u30b3\u30d7\u30ec\u30df\u30a2\u30e0", "cost": 385, "period": "monthly", "userid": "(ユーザーID)", "update_date": "2024-06-01"}]
レスポンスヘッダー
{
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Origin": "*",
"X-Amzn-Trace-Id": "Root=1-66527ea8-4f0f4b6659e36020ffd57ab9;Parent=4e327a9e5f158d86;Sampled=0;lineage=c412f566:0"
}
PUT=>update_item()
リクエスト本文に以下のJSONを設定してテスト実行
{"operation":"update",
"payload":{
"Key":{ "userid": "(ユーザーID)","subs_name":"Netflix"},
"UpdateExpression":"SET cost = :cost",
"ExpressionAttributeValues":{":cost": 1490}
}
}
以下のような結果が返ってきたため、成功
/DynamoDBManager - PUT メソッドテストの結果
リクエスト
/DynamoDBManager
レイテンシー ms
102
ステータス
200
レスポンス本文
{"message": "Item updated successfully"}
レスポンスヘッダー
{
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Origin": "*",
"X-Amzn-Trace-Id": "Root=1-66527ee8-cf05c5e855e573a4f116c697;Parent=7147d67fc8e7e895;Sampled=0;lineage=c412f566:0"
}
DELETE=>delete_item()
リクエスト本文に以下のJSONを設定してテスト実行
{"operation":"delete","payload":{"Key":{ "userid": "(ユーザーID)","subs_name":"Netflix"}}}
以下のような結果が返ってきたため、成功
/DynamoDBManager - DELETE メソッドテストの結果
リクエスト
/DynamoDBManager
レイテンシー ms
485
ステータス
200
レスポンス本文
{"message": "Item deleted successfully"}
レスポンスヘッダー
{
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Origin": "*",
"X-Amzn-Trace-Id": "Root=1-66527f4b-f012b9d4c2af9835912a23b7;Parent=20337fe346708d8b;Sampled=0;lineage=c412f566:0"
}