AWS API GatewayとLambdaでDynamoDB操作

AWS Lambdaの一般的な利用方法の中から1つを取り上げ、環境構築からLambda関数の作成および動作確認までの一連の作業手順を詳細に解説しています。

今回はDynamoDBを操作するLambdaの作成手順を解説します。

また今回はLambdaの起動するサービスとしてAmazon API Gatewayを使用します。Amzon API Gatewayを使用することで、LambdaをREST APIとして外部ネットワークから利用することができます。

Amazon API GatewayでのREST API作成から外部ネットワークからのアクセス確認手順についても併せて解説します。

LambdaとAmazon API Gatewayの組み合わせは、外部ネットワークで動作しているアプリケーションからDynamoDBやS3などのAWSサービスにアクセスする際によく使用される形態のひとつです。

ユースケースとしては以下のようなものがあります。

  • ホテルの予約アプリからDynamoDB上にある客室の利用データにアクセスし、空き室状況の確認や予約を行う
  • 座席予約アプリからDynamoDB上にある座席データにアクセスし、座席予約状況の確認や予約を行う

動作概要

動作の全体像を以下に示します。

動作概要

Amazon API GatewayがユーザからHTTPリクエストを受信すると、登録しているLambdaを起動します。
起動されたLambda関数は、引数からDynamoDBの操作要求を抽出して要求に応じた操作(全レコードスキャン/指定レコード検索/レコードの追加・更新/レコードの削除)を実行し、結果を応答します。
Amazon API GatewayはLambdaから受け取った応答メッセージをユーザへ返信します。

DynamoDBテーブル作成

サンプル用のDBを作成します。今回はデバイスに搭載された温度、湿度センサーの計測値を管理するDBを以下の内容で作成します。

キー設定 カラム名 意味 記事
パーティションキー DeviceID 装置識別子 DevXXXX
※XXXX:0001からの整数
ソートキー SensorID センサー識別子 温度:TempXXX
湿度:HumXXX
※XXX:001からの整数
value 値(温度/湿度) 整数
unit 単位 温度:℃/湿度:%

テーブル作成

DynamoDBコンソール画面から「テーブル作成」ボタンを押下します。

テーブル作成画面で以下を設定し、画面右下の「作成」ボタンを押下します。

  • テーブル名に「SensorTables」を設定
  • パーティションキーに「DeviceID」を設定
  • 「ソートキーの追加」にチェックを入れ、ソートキーに「SensorID」を設定

レコード作成

動作確認用に幾つかのレコードを作成します。

DynamoDBのコンソール画面から「テーブル」のメニュー画面を開きます。
「テーブル」一覧から「SensorTables」を選択します。
「SensorTables」の設定画面から「項目」タブを選択します。
「項目」タブの画面から「項目の追加」ボタンを押下します。

「項目の作成」画面が開くので、以下を設定します。

  • DeviceDに「Dev0001」を設定
  • SensorIDに「Temp001」を設定
  • SensorIDの「+」ボタンをクリック。ポップアップメニューから「Append」を選択
  • 「Append」のドロップダウンリストから「Number」を選択

  • 左側の入力欄に「value」と設定
  • 右側の入力欄に任意の温度を設定(下図では2を設定)
  • valueの「+」ボタンをクリック。ポップアップメニューから「Append」を選択
  • 「Append」のドロップダウンリストから「String」を選択
  • 左側の入力欄に「unit」と設定
  • 右側の入力欄に「℃」と設定

最後に画面右下の「保存」ボタンを押下します。

湿度のレコードを作成します。
「SensorTables」の設定画面から「アクション」ボタンを押下します。
ドロップダウンリストから「コピー」を選択します。

「項目の作成」画面が開くので、以下を設定します。

  • SensorIDに「Hum001」を設定
  • valueに任意の湿度を設定(下図では25を入力)
  • unitに「%」を設定

最後に画面右下の「保存」ボタンを押下します。

同様の手順でDeviceIDがDev0003までの温度&湿度センサーレコードを作成します。

valueの値は任意の整数で入力してください。下図の値に合わせる必要はありません。

IAMロール作成

LambdaがDynamoDBにアクセスするためのIAMロールを作成します。

IAMコンソール画面の左ペインから「ロール」を選択します。
「ロール」の設定画面から「ロールの作成」ボタンを押下します。

「ロールの作成」画面からデフォルトで選択されている「AWSサービス」を選択し、「ユースケースの選択」一覧から「Lambda」を選択します。

「ユースケースの選択」画面が表示されるので「次のステップ:アクセス権限」ボタンを押下します。

「Attachアクセス権限ポリシー」作成画面が表示されるので「ポリシーのフィルタ」のキーワード入力欄に「dynamo」と入力します。
表示された候補から以下を選択し、「次のステップ:タグ」ボタンを押下します。
「AmazonDynamoDBFullAccess」
「AWSLambdaDynamoDBExecutionRole」

「タグの追加(オプション)」設定画面では何もせず、「次のステップ:確認」ボタンを押下します。

「確認」画面が表示されるので「ロール名」に「LambdaAccess2DynamoDB」と入力し、「ロールの作成」ボタンを押下します。

ロールの作成が完了するとロールの一覧に作成した「LambdaAccess2DynamoDB」が登録されます。

Lambda作成

DynamoDBの操作を行うLambda関数を作成します。

Lambda関数登録

Lambdaの作成方法には以下の2通りがあります。
①AWS Lambdaコンソールで直接コードを作成。
②外部ライブラリとLambda関数をパッケージ化してアップロード。
今回はDynamoDBの操作のみで外部ライブラリを必要としないため、①での作成になります。

Lambdaコンソールから「関数の作成」ボタンを押下します。「関数の作成」画面のオプションの中から「一から作成」を選択します。

「基本的な情報」画面が表示されるので以下を設定します

  • 「関数名」に「HeatHumiditySensorSet」と入力
  • 「ランタイム」に「python3.8」を選択
  • 「実行ロールの選択または作成」をクリックし、折り畳まれている画面を表示

「実行ロール」の候補の中から「既存のロールを使用する」を選択

キーワード入力欄に「LambdaAccess」と入力。
表示された候補から「LambdaAccess2DynamoDB」を選択
「関数の作成」ボタンを押下

Lambda関数の修正

デフォルトで提供されているLambda関数を編集してDynamoDBを操作するコードを作成します。

コード内容を以下に示します。

import json
import boto3

from boto3.dynamodb.conditions import Key	//Keyオブジェクトを利用できるようにする

dynamodb = boto3.resource('dynamodb')	//Dynamodbアクセスのためのオブジェクト取得
table = dynamodb.Table("SensorTables")	//指定テーブルのアクセスオブジェクト取得

# テーブルスキャン
def operation_scan()::
    scanData = table.scan()	//scan()メソッドでテーブル内をscan。一覧を取得
    items=scanData['Items']	//応答からレコード一覧を抽出
    print(items)	//レコード一覧を表示
    return scanData

# レコード検索
def operation_query(partitionKey, sortKey):
    queryData = table.query(	//query()メソッドでテーブル内を検索
        KeyConditionExpression = Key("DeviceID").eq(partitionKey) & Key("SensorID").eq(sortKey)	//検索キー(DeviceIDとSensorID)を設定
    )
    items=queryData['Items']	//応答から取得レコードを抽出
    print(items)	//取得レコードを表示
    return queryData

# レコード追加・更新
def operation_put(partitionKey, sortKey, value, unit):
    putResponse = table.put_item(	//put_item()メソッドで追加・更新レコードを設定
        Item={	//追加・更新対象レコードのカラムリストを設定
            'DeviceID': partitionKey,
            'SensorID': sortKey,
            'value': value,
            'unit': unit
        }
    )
    if putResponse['ResponseMetadata']['HTTPStatusCode'] != 200:	//HTTPステータスコードが200 OKでないか判定
        print(putResponse)	//エラーレスポンスを表示
    else:
        print('PUT Successed.')
    return putResponse

# レコード削除
def operation_delete(partitionKey, sortKey):
    delResponse = table.delete_item(	//delete()メソッドで指定テーブルを削除
       key={	//Keyオブジェクトで削除対象レコードのキー設定
           'DeviceID': partitionKey,
           'SensorID': sortKey
       }
    )
    if delResponse['ResponseMetadata']['HTTPStatusCode'] != 200:	//HTTPステータスコードが200 OKでないか判定
        print(delResponse)	//エラーレスポンスを表示
    else:
        print('DEL Successed.')
    return delResponse

def lambda_handler(event, context):	//Lambdaから最初に呼びされるハンドラ関数
    print("Received event: " + json.dumps(event))	//引数:eventの内容を表示
    OperationType = event['OperationType']	//引数から操作タイプを取得
    try:
        if OperationType == 'SCAN':	//OperationTypeが'SCAN'か判定
            return operation_scan()
        PartitionKey = event['Keys']['DeviceID']	//引数からDeviceIDの値を取得
        SortKey = event['Keys']['SensorID']	//引数からSensorIDの値を取得
        if OperationType == 'QUERY':	//OperationTypeが'QUERY'か判定
            return operation_query(PartitionKey, SortKey)
        elif OperationType == 'PUT':	//OperationTypeが'PUT'か判定
            Value = event['Keys']['value']	//引数からvalueの値を取得
            Unit = event['Keys']['unit']	//引数からunitの値を取得
            return operation_put(PartitionKey, SortKey, Value, Unit)
        elif OperationType == 'DELETE':	//OperationTypeが'DELETE'か判定
            return operation_delete(PartitionKey, SortKey)
    except Exception as e:
        print("Error Exception.")
        print(e)

(※)LambdaからDynamoDBへのアクセスにはAWS SDK for Python(boto3)を使用します。

boto3全体のドキュメントは「Boto 3 Documentation別ウィンドウで開きます」を参照してください
boto3でのDynamoDBについての記載は「DynamoDB別ウィンドウで開きます」を参照してください

(※) boto3ではDynamoDBのテーブル操作手段として2種類のクラスが提供されています。

  • DynamoDB.Client()
  • DynamoDB.Table()

DynamoDB.Client()はDynamoDBの全般の操作が可能なクラスで、DynamoDB.Table()はテーブル操作に特化したクラスです。テーブル操作に特化している分、操作性が良いので今回はDynamoDB.Table()クラスを使用します。

以下にDynamoDB.Table()クラスの使用方法とそれぞれのメソッド仕様を解説します。

準備
import boto3	//boto3をインポート
from boto3.dynamodb.conditions import Key	//boto3.dynamodb.conditionsのKeyクラスをインポート
dynamodb = boto3.resource('dynamodb')	//DynamoDBアクセスのためのオブジェクトを取得
table = dynamodb.Table("テーブル名")	//引数のテーブルへのアクセスのためのオブジェクトを取得
scan

テーブル内の全レコードをスキャンし、取得したレコード一覧を返します。

書式:

response = table.scan()

戻り値:

レコード一覧(dict形式)

query

主キーに基づいてアイテムを検索します。パーティションキーとソートキーの複合キーでの検索も可能です。

書式:

response = table.query(
           KeyConditionExpression=Key('key1').eq('keyValue1')
           )

引数:

KeyConditionExpression=Key('mykey').eq('myvalue')
	KeyConditionExpression:キー、インデックスによる検索の定義
		'mykey':キー名
		'myvalue':キー値
        複合キーの場合はKey('key1').eq('keyValue1')& Key('key2').eq('keyValue2')としてください。
queryはKeyConditionExpression以外にも設定可能な引数があります。詳細はquery(**kwargs)別ウィンドウで開きますを参照してください。

戻り値:

検索条件に一致したレコード(dict形式)

put

テーブル内に引数のレコードを設定します。テーブル内に引数のレコードが存在しない場合は新たに追加し、存在する場合は引数の内容で上書き更新します。
(※)引数で設定した内容をそのまま設定するため、更新時でも全ての要素を設定する必要があります。引数にない要素は空欄として設定されます。

書式:

response = table.put_item(
           Item={'key1': 'keyValue1', 'key2': 'keyValue2', 'column1': ' columnValue1',・・・}
           )

引数:

Item={'key1': 'keyValue1', 'key2': 'keyValue2', 'column1': ' columnValue1',・・・}
テーブルに設定するアイテム。
(※)dict形式でプライマリーキー、ソートキーの他、レコード内の要素を全て設定してください

戻り値:

実行結果(dict形式)

delete

指定したキーに一致するレコードを削除します。

書式:

response = table.delete_item(
           Key={'key1': keyValue1', 'key2': 'keyValue2'}
           )

引数:

Key={'key1': keyValue1', 'key2': 'keyValue2'}
dict形式でプライマリーキー、ソートキーを設定

戻り値:

実行結果(dict形式)

Lambda関数「HeatHumiditySensorSet」のメニュー画面を「関数コード」の設定欄まで画面をスクロールします。
関数コードを上記の内容に書き替えます。
画面右上の「保存」ボタンを押下して関数コードの内容を保存します。

API Gateway作成

Amazon API Gatewayのコンソール画面から「APIを作成」ボタンを押下します。

「APIタイプの選択」画面で「REST API」を選択し「構築」ボタンを押下します。

以下を設定し、画面右下の「APIの作成」ボタンを押下します。

  • 「プロトコルを選択する」で「REST」を選択
  • 「新しいAPIの作成」で「新しいAPI」を選択
  • 「名前と説明」でAPI名に「LambdaRest」を設定

APIが作成されると「API:LambdaRest」のトップページが開きます。
「アクション」ボタンを押下し、ドロップダウンリストから「リソースの作成」を選択します。

リソースとはWeb APIのパスになります。
デフォルトは「/」で、これにパスを設定することにより、パス毎に別々のLambda関数を割り振ることが出来ます。接続先を割り振る必要がない場合は不要です。
今回は複数の接続先は用意していませんが、設定手順の紹介のため設定します。

「リソース名」に「dynamodbctrl」と設定し、面右下の「リソースの作成」ボタンを押下します。

「アクション」ボタンを押下し、ドロップダウンリストから「メソッドの作成」を選択します。

「/dynamodbctrl」の下にメソッド設定用の空欄が作成されますのでクリックします。
ドロップダウンリストから「POST」を選択します。

「POST」の右横にある「✓」を押下します。

「POSTのセットアップ」画面が開くので以下を設定し画面右下の「保存」ボタンを押下します。

  • 「結合タイプ」に「Lambda関数」を選択
  • 「Lambda関数」の入力欄に「HeatHumiditySensorSet」を設定

「保存」ボタンを押下すると「Lambda関数に権限を追加する」というポップアップメッセージが表示されるので「OK」ボタンを押下してください。

これによりPOSTメソッドリクエストがLambda関数「HeatHumiditySensorSet」に渡されるルートが確立されます。

この設定によりLambda関数「HeatHumiditySensorSet」に自動的にAPI Gatewayのトリガーが設定されます。

APIテスト

API Gateway内部でのテストを実施し、API GatewayのAPI設定とLambda関数の動作確認を実施します。
「POST – メソッドの実行」画面で「テスト」ボタンを押下します。

「POST –メソッドテスト」の入力画面が開きます。

「リクエスト本文」にLambda関数に渡すメッセージをJSON形式で入力し、「テスト」ボタンを押下します。
図はテーブルスキャン要求の入力例になります。

Lambda関数「HeatHumiditySensorSet」に渡すメッセージは以下のように作成します。

操作 意味 リクエスト本文 記事
SCAN スキャン {
"OperationType": "SCAN"
}

操作タイプにSCANを設定
QUERY 検索 {
"OperationType": "QUERY",
"Keys": {
"DeviceID":"DevXXXX",
"SensorID":"XXX00X"
}

操作タイプにQUERYを設定
Keys:検索用のキーを定義
"DevXXXX":(※)XXXX:0001からの整数
"XXX00X":(※)TempXXX or HumXXX
※XXX=001からの整数
PUT 追加/変更 {
"OperationType": "PUT",
"Keys": {
"DeviceID":"DevXXXX",
"SensorID":" XXX00X",
"value":XX,
"unit":"X"
}

操作タイプにPUTを設定
Keys:追加/変更対象のレコード内容を定義
"DevXXXX":(※)XXXX:0001からの整数
"XXX00X":(※)TempXXX or HumXXX
※XXX=001からの整数
DELETE 削除 {
"OperationType": "DELETE",
"Keys": {
"DeviceID":"DevXXXX",
"SensorID":"XXX00X"
}

操作タイプにDELETEを設定
Keys:削除対象レコードのキーを定義
"DevXXXX":(※)XXXX:0001からの整数
"XXX00X":(※)TempXXX or HumXXX
※XXX=001からの整数

テストを実行すると、メソッドテスト画面右側に応答情報が表示されます。
図はテーブルスキャンを実施した際の応答になります。

Lambdaのログからも動作内容を確認することが出来ます。
Lambda関数「HeatHumiditySensorSet」のメニュー画面から「モニタリング」タブを選択します。
「モニタリングタブ」画面から「CloudWatchのログを表示」を選択します。

Lambda関数「HeatHumiditySensorSet」のロググループにジャンプします。
ログストリームのリストに表示されているファイルをクリックすると、Lambda関数のログ詳細を見ることが出来ます。

図はテーブルスキャンを実施した際のログになります。

APIの公開

作成したAPIを外部に公開して外部ネットワークからアクセスできるようにします。
APIをデプロイすることによりAPIが外部に公開されます。

APIデプロイ

「POST – メソッドの実行」画面で「アクション」ボタンを押下します。
ドロップダウンリストから「APIのデプロイ」を選択します。

「APIのデプロイ」画面が開くので以下を設定し「デプロイ」ボタンを押下します。

  • 「デプロイされるステージ」に「新しいステージ」を選択
  • 「ステージ名」に「APItest」と設定(※)

※ステージ名は以下のようにAPIのURLの一部に使用されます。

https://{restapi_id}.execute-api.{region}.amazonaws.com/{stage_name}/

※{restapi_id} : API ID(一意性を持ったAPIの識別子)
  {region} :リージョン	
  {stage_name} :ステージ名

APIのデプロイに成功すると、「ステージエディター」が表示され、APIにアクセスするためのURLが表示されます。

接続テスト

公開されたAPIに対し、外部からアクセス可能か確認します。
アクセス確認にはcurlコマンドやAPI開発ツール「Postman別ウィンドウで開きます」を使う方法などがあります。今回はcurlコマンドでの接続テスト方法について解説します。

Amazon API Gatewayへは、以下の書式でcurlコマンドを実行してください。

curl –X POST https://URL -d PARAM | jq
POSTメソッドでAPIを作成したので、POSTでリクエストします。
URLは「ステージエディター」で表示されているURLを使用します。
末尾にパスとして「リソースの作成」で作成した「/dynamodbctrl」を付加します。
PARAMには「5. APIテスト」のLambda関数「HeatHumiditySensorSet」に渡すメッセージとして示したものを設定します。
jqコマンドを使用して、応答メッセージを整形して見易くします。

以下にDynamoDBに対し、scan, query, put, deleteそれぞれの入力例と実行例を示します

scan

入力例

$ curl -X POST 'https://XXXXXX.execute-api.ap-northeast-1.amazonaws.com/APItest/dynamodbctrl' -d '{"OperationType":"SCAN"}' | jq

実行例

レコードリストが返信されます。jqコマンドにより応答メッセージが整形されます。

query

入力例

$ curl -X POST 'https://XXXXXX.execute-api.ap-northeast-1.amazonaws.com/APItest/dynamodbctrl' -d '{"OperationType":"QUERY","Keys":{"DeviceID": "Dev0003", "SensorID": "Temp003"}}' | jq

実行例

Dev0003, Temp003のレコードが返信されます。jqコマンドにより応答メッセージが整形されます。

put

入力例

$ curl -X POST 'https://XXXXXX.execute-api.ap-northeast-1.amazonaws.com/APItest/dynamodbctrl' -d '{"OperationType":"PUT","Keys":{"unit": "\u2103", "value": 23, "DeviceID": "Dev0005", "SensorID": "Temp005"}}' | jq

実行例

実行結果が返信されます。jqコマンドにより応答メッセージが整形されます。

DyanamoDBのコンソールで「SensorTables」の設定画面からDeviceID:Dev0005, SensorID:Temp005のレコードが追加されたことが確認できます。

delete

入力例

$ curl -X POST 'https://XXXXXX.execute-api.ap-northeast-1.amazonaws.com/APItest/dynamodbctrl' -d ' {"OperationType":"DELETE","Keys":{"DeviceID": "Dev0005", "SensorID": "Temp005"}}' | jq

実行例

実行結果が返信されます。jqコマンドにより応答メッセージが整形されます

DyanamoDBのコンソールで「SensorTables」の設定画面からDeviceID:Dev0005, SensorID:Temp005のレコードが削除されたことが確認できます。

あとがき

DynamoDBの操作を行うLambdaと、LambdaをREST APIとして外部ネットワークに公開するAmazon API Gatewayの作成手順と環境構築から外部ネットワークからのアクセス確認手順まで解説しました。

LambdaでのDynamoDBの操作方法、Amazon API GatewayでのREST API作成と外部への公開方法などが理解できたと思います。

Amazon API GatewayとLambdaの組み合わせは外部ネットワークからREST APIとしてAWSサービスを利用できるため、手軽にAWSサービスを利用したWebアプリケーションを開発することができます。

やはり難しい??事例からAWS Lambda活用のヒントを得ましょう!

一歩進んだAWS Lambda活用!ローカル環境での活用方法を学びましょう。

Amazon Web Services(AWS)、Microsoft Azureの
導入支援サービスのご相談、お問い合わせをお待ちしております。

ページ上部へ戻る