Lambda+API GatewayからDynamoDBにアクセスする方法
はじめに
今回の記事の目的
Lambda関数を作成し、DynamoDBにアクセスする。 Lambda関数を呼び出すためにAPI Gatewayを利用する。
IAMロールを作成する
「DynamoDBにアクセスする権限」を「Lambdaに」与える。
- IAMコンソールの「ロール」画面から「ロールの作成」。
- ユースケースの選択で「Lambda」を選択。
- Attach アクセス権限ポリシーで以下を選ぶ。
- AWSLambdaBasicExecutionRole
- AmazonDynamoDBFullAccess
以下の通り作成した。
API Gateway
Lambdaプロキシ統合
Lambdaプロキシ統合という仕組みを利用する。 HTTPSで受信したデータをLambda関数に自動的に渡したり、Lambda関数から戻ってきたデータを整形してHTTPSで戻す仕組み。
Lambda関数の定義
def lambda_handler(event , context)
- eventは、呼び出し元の情報。例えばAPI Gatewayだったら、ブラウザから送信された値を持つ。
- contextは、実行環境(Lambdaコンテナの環境)に関する情報。割り当てられたメモリなど。
Lambda関数の戻り値
Lambda関数からの戻り値は、API GatewayのLambdaプロキシ統合の場合決まっている。
{ 'statusCode':'200', 'headers':{ 'content-type':コンテンツタイプ }, 'body' : 本文データ }
Lambda関数とAPI Gatewayを作成する
- マネジメントコンソールから「Lambda」を選択
- 「関数」→「関数の作成」
設計図の選択
- 今回は「設計図から作成」を選択する。
AWSがもともと作っているサンプルをもとに作成する。
- 今回は「microservice-http-endpoint-python」を選ぶ。
Node.jsで作りたい場合は「microservice-http-endpoint」を選ぶ。
基本設定
以下の通り基本設定をした。IAMロールは先ほど作ったものを選択する。
API Gatewayの設定
以下の通りAPIの設定をした。
セキュリティは
- オープン
- JWT オーソライザーを作成
から選択する。今回は公開APIとするためオープンを選択した。
JWTオーソライザーについては割愛。
JWT オーソライザーを使用した HTTP API へのアクセスの制御 - Amazon API Gateway
Lambda関数のコード
今回pythonを利用して記載する。
boto3のインポート
AWSサービスを使うためのpythonモジュールboto3
をインポートして、DynamoDBを利用する。
import json import boto3 dynamodb = boto3.resource('dynamodb')
lambda関数の定義
lambda関数を定義する。
def lambda_handler(event, context):
※これ以下のコードはすべてlambda_handlerの中身なので、インデントを下げて記載する。
DynamoDBのテーブルから値を取得する。
keijitable = dynamodb.Table("ay-s-keijiban") # テーブルを変数に入れる response = keijitable.scan() # テーブルの全データを取得するメソッド。あまり大きいと全部読み取れないので注意。
HTMLの作成
返却したいHTMLを作成する。
html = "<html>・・・・・</html>"
注意:""
の中で"
を使いたい場合はエスケープする必要がある。(例:<meta charset=\"UTF-8\">
)
HTMLを作成する中で、取得したデータを利用する。
for data in sorted(response["Items"], reverse=True, key=lambda d: d["postat"]): ・・・・ ・・・・
for文の構文
for 変数名 in オブジェクト :
sortedの構文
sorted()
は、ソートした新たなリストを生成するメソッド。
sorted( 元のリスト, 引数)
引数reverse
は、True
とすると降順にソートする。
また、引数key
は、
key=lambda x: x[1]
とすることで、1番目の要素をキーとしてソートできる。
key=lambda x: x["postat"]
でpostat
項目を要素としてソートできる。
sortedの資料
[解決!Python]リスト(配列)をソートしたり、逆順にしたりするには(sort/reverseメソッド、sorted/reversed関数):解決!Python - @IT
返却項目作成
最後に返却するJSONを作成する。
return { 'statusCode':'200', 'headers':{ 'content-type':'text/html' }, 'body' : html }
pythonのポイント
以下の講座を参考にした。コードはコピペできないので重要要素だけメモ。
AWS Lambdaを活用したサーバレス実践 -第3回- - Schoo(スクー)
Lambda関数をテストする
「Test」→「Configure test event」を選択。
イベントテンプレートは「apigateway-aws-proxy」を選択。
要求電文は特に変更しない。
エラー発生 #1
以下のエラーが発生した。
[ERROR] JSONDecodeError: Expecting value: line 1 column 1 (char 0) Traceback (most recent call last): File "/var/task/lambda_function.py", line 39, in lambda_handler payload = event['queryStringParameters'] if operation == 'GET' else json.loads(event['body']) File "/var/lang/lib/python3.7/json/__init__.py", line 348, in loads return _default_decoder.decode(s) File "/var/lang/lib/python3.7/json/decoder.py", line 337, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "/var/lang/lib/python3.7/json/decoder.py", line 355, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None
原因は、デプロイをする前にテストしていたことである模様。
設計図にもともと記載があったコードを実行してしまっていたようだった。
エラー発生 #2
デプロイしてからテストしたところ、以下のエラーが発生。
START RequestId: XXXXXXXXXXXX Version: $LATEST [ERROR] KeyError: 'items' Traceback (most recent call last): File "/var/task/lambda_function.py", line 14, in lambda_handler for data in sorted(response["items"], reverse=True, key=lambda d: d["postat"]): END RequestId: XXXXXXXXXXXX REPORT RequestId: XXXXXXXXXXXX Duration: 72.25 ms Billed Duration: 73 ms Memory Size: 512 MB Max Memory Used: 69 MB Init Duration: 372.27 ms
原因は、以下のコードの Items
がitems
になっていたタイプミスだった。
for data in sorted(response["Items"], reverse=True, key=lambda d: d["postat"]):
Lambda関数のコードに書いているファイル名はlambda_function.py
となる。
CloudWatch logs
テスト実行結果からCloudWatch logsに遷移して、以下のようにログを見ることができる。
テスト成功
諸々修正してテストが成功した。
APIを打鍵してみる
API Gatewayのエンドポイントを確認して、打鍵してみる。
確認結果
APIをブラウザから打鍵できた。
おわりに
Lambda+API Gatewayを利用してAPIを作成する方法がわかった。 また、pythonからDynamoDBにアクセスする方法がわかった。