エンジニアを目指す日常ブログ

日々勉強したことのメモ。独学ですので間違っていたらコメント等で教えてください。

Lambda+API GatewayからDynamoDBにアクセスする方法

はじめに

今回の記事の目的

Lambda関数を作成し、DynamoDBにアクセスする。 Lambda関数を呼び出すためにAPI Gatewayを利用する。

IAMロールを作成する

「DynamoDBにアクセスする権限」を「Lambdaに」与える。

  • IAMコンソールの「ロール」画面から「ロールの作成」。
  • ユースケースの選択で「Lambda」を選択。
  • Attach アクセス権限ポリシーで以下を選ぶ。
    • AWSLambdaBasicExecutionRole
    • AmazonDynamoDBFullAccess

以下の通り作成した。

IAMロール作成の確認画面
IAMロール作成の確認画面

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がもともと作っているサンプルをもとに作成する。

設計図からLambda関数を作成
設計図からLambda関数を作成

  • 今回は「microservice-http-endpoint-python」を選ぶ。
    Node.jsで作りたい場合は「microservice-http-endpoint」を選ぶ。

基本設定

以下の通り基本設定をした。IAMロールは先ほど作ったものを選択する。

基本設定
基本設定

API Gatewayの設定

以下の通りAPIの設定をした。

セキュリティは

  • オープン
  • JWT オーソライザーを作成

から選択する。今回は公開APIとするためオープンを選択した。

JWTオーソライザーについては割愛。
JWT オーソライザーを使用した HTTP API へのアクセスの制御 - Amazon API Gateway

API Gatewayの設定
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のポイント
  • Java等では{ }で囲むが、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

原因は、以下のコードの Itemsitemsになっていたタイプミスだった。

for data in sorted(response["Items"], reverse=True, key=lambda d: d["postat"]):

Lambda関数のコードに書いているファイル名はlambda_function.pyとなる。

CloudWatch logs

テスト実行結果からCloudWatch logsに遷移して、以下のようにログを見ることができる。

CloudWatch
CloudWatch

テスト成功

諸々修正してテストが成功した。

テスト成功
テスト成功

APIを打鍵してみる

API Gatewayのエンドポイントを確認して、打鍵してみる。

エンドポイントの確認
エンドポイントの確認

確認結果

APIをブラウザから打鍵できた。

ブラウザから打鍵した結果
ブラウザから打鍵した結果

おわりに

Lambda+API Gatewayを利用してAPIを作成する方法がわかった。 また、pythonからDynamoDBにアクセスする方法がわかった。

関連記事

前回までの記事

DynamoDBでテーブルを作成して、データを追加する。

tomiko0404.hatenablog.com