目的
AWSでよくある構成として APIgateway+Lambda+DynamoDBのサーバレスな構成があります。
ただこの時に、DynamoDBでは連番の管理ができない(id1の次は2のidをつけるみたいな)
そのため、DynamoDB側でテーブルを二つ用意してあげる必要があります。
- データを格納テーブル(例: id,名前,email,時刻など)
- 連番を管理するテーブル(上記のidの部分をカウントするようのテーブル)
そのためLambdaでカウントするようなコードの書き方になってきます。
前提としてLambda,APIgateway,DynamoDB間のAMIの権限周りは既にクリアした前提とします。
やったこと
今回は、Lambdaのコード周りでハマりまくったので
備忘録的な感じでコードだけとりあえず貼っておきます。
import json
import boto3
import base64
import time
import decimal
# DynamoDBオブジェクト
dynamodb = boto3.resource('dynamodb')
# 連番を更新して返す関数
def next_seq(table, tablename):
response = table.update_item(
Key={
'tablename' : tablename
},
UpdateExpression='set seq = seq + :val',
ExpressionAttributeValues= {
':val' : 1
},
ReturnValues='UPDATED_NEW'
)
return response['Attributes']['seq']
def lambda_handler(event, context):
try:
# シーケンスデータを得る
seqtable = dynamodb.Table('kuruma-sequence')
nextseq = next_seq(seqtable, 'kuruma-user')
# フォームに入力されたデータを得る
body = event['body']
if event['isBase64Encoded']:
body = base64.b64decode(body)
decoded = json.loads(body)
username = decoded['username']
email = decoded['email']
# クライアントのIPアドレスを得る
host = event['requestContext']['identity']['sourceIp']
# 現在のUNIXタイムスタンプを得る
now = time.time()
# ユーザーテーブルを登録する
usertable = dynamodb.Table('kuruma-user')
usertable.put_item(
Item={
'id' : nextseq,
'username' : username,
'email' : email,
'accepted_at' : decimal.Decimal(str(now)),
'host' : host
}
)
# 結果を返す
return {
'statusCode' : 200,
'body' : json.dumps({})
}
except:
# エラー文を返す
import traceback
err = traceback.format_exc()
print(err)
return{
'statusCode' : 500,
'headers' :{
'context-type' : 'text/json'
},
'body' : json.dumps({
'error' : '内部エラーが発生しました'
})
}
しょうもないところでハマった
クライアント側のIPアドレスを取得する時に書き方がわからずハマった。
最初はずっと下記のような書き方をしていました。
ですがずっと KeyError 'host'でひっかかっている
ドキュメントみても'host'はあったので何がいけないのかわからずで、Lambda側のテストの中身見ていると'identity'になっていたので、試しに書き換えてみると取得できるようになっていました。
ハマっていたコード
# クライアントのIPアドレスを得る
host = event['requestContext']['host']['sourceIp']
↓
成功したコード
# クライアントのIPアドレスを得る
host = event['requestContext']['identity']['sourceIp']