7rikazhexde’s tech log

技術的な興味関心、備忘録、アウトプットなどを書いています。

【AWS】API Gateway + Lambda + DynamoDB構成でGETリクエストで DBのデータ(json)を取得して、 DataFrameを作成する

前書き

これまでは私はクラウド(AWS)と通信するデバイス側の開発(組込みデバイス、デスクトップアプリ)が中心でした。I/Fの仕様が決まれば通信はできますが、サービスを作る上でクラウド側の知識がないとエンジニアとして面白みがないなと感じることが増えてきました。これは現業が類似した業務の繰り返しでエンジニアとしてこのままで良いのかという危機感的な部分もありますが、スキルを増やしたいというモチベーションが強いです。

個人的な経験からクラウドの運用にはコストはかかりますが、アイデアを具現化することに関して、短期的に拡張性を考慮して実現することに利点があると考えています。何だかんだ見栄えも良いです。また、その中心はクラウドという印象です。いくらデバイスが良くても、データを取得、分析、解析までできなければ、使えるサービスにはなりません。各工程のスキルを身に付けることは簡単なことではありませんが、作りたいものの選択肢は拡がると思います。

一方で、ちょうど業務でAWSのサービスを使うことになり、良い機会なので、プライベートでもアカウントも作成して触りながら知識を深めていこうと思い、コードを書いてAWSのサービスを使ってみることにしました。

前置きが長くなりましたが、本記事はクラウドを触ってみた記事であり、AWSのサービスとして、API Gateway, Lambda, DynamoDBを使用した記事になります。

前提条件

  • AWSアカウント(ルートユーザー)を作成済みであること

ソースコード

ソースコードGitHubにコミットしています。

github.com

IAMユーザー作成

ルートユーザーでログインし、「IAMユーザーを作成する 」を指定して作成します。

ステップ 1 ユーザーの詳細を指定

  • ユーザー名:[割愛]
  • AWS マネジメントコンソールへのユーザーアクセスを提供する - オプション:チェック
    • IAMユーザーを作成します:選択
    • コンソールパスワード
      • 自動生成されたパスワード
    • ユーザーは次回のサインイン時に新しいパスワードを作成する必要があります - 推奨:チェック

ユーザーは次回のサインイン時に新しいパスワードを作成する必要があります」という項目については、チェックをつけます。 自動作成だと文字数が少ないため、ログイン時に変更した方が良いと思いました。
また、作成後は参照できませんが、作成直後はコピー、csv保存が可能です。

補足: IAMユーザー作成時の選択肢

chatgptより引用(2023/11/05時点)

AWSのIAMユーザー作成時には、以下の2つの選択肢があります。

  1. Identity Centerでユーザーを指定する - Identity Centerでは、AWSアカウントおよびクラウドアプリケーションへのユーザーアクセスを一元管理できます。これは推奨される方法です。
  2. IAMユーザーを作成する - アクセスキー、AWS CodeCommit または Amazon Keyspaces のサービス固有の認証情報、または緊急アカウントアクセス用のバックアップ認証情報を使用してプログラムによるアクセスを有効にする必要がある場合のみ、IAMユーザーの作成が推奨されます。

一般的には、Identity Centerでユーザーを指定することが推奨されています。これにより、AWSアカウントおよびクラウドアプリケーションへのユーザーアクセスを一元管理できます。ただし、プログラムによるアクセスを有効にする必要がある場合は、IAMユーザーの作成を選択することもあります。どちらの選択肢を選ぶかは要件によります。

また、「Identity Centerでユーザーを指定する」場合は、AWS Organizationsを有効化する必要があります。AWS Organizationsは、複数のAWSアカウントを一元管理するためのサービスです。これにより、単一の支払い者と一元化されたコスト追跡が可能になり、他のAWSアカウントを作成して招待したり、ポリシーベースのコントロールを適用したりすることができます。

今回は個人利用で複数のAWSアカウントを管理する必要がないため、「IAMユーザーを作成します」で作成しました。

ステップ 2 許可を設定

  • 許可のオプション:ポリシーを直接アタッチする(AdministratorAccessを指定)

ステップ 3 確認して作成

ユーザーの詳細、許可の概要、タグ(オプション)を確認し、問題がなければ、ユーザーの作成を押下する。
タグ(オプション)は必要に応じて設定する。

ステップ 4 パスワードを取得

パスワード情報をコピー、csv保存し、完了

参考記事

IAMユーザーのアクセスキー作成

AWSの各サービスを利用するためにはアクセスキーが必要になります。アカウント作成時はアクセスキーを自動で作成する選択肢もあったかと思いますが、基本的にはIAMユーザー作成後にアクセスキーを作成します。以下の指定で作成します。

IAMユーザー > セキュリティ認証情報 > アクセスキーを作成 > ユーザーケース選択(※) > 次へ

AWS CLI V2で認証情報を設定、コードで参照する方式のため、コマンドラインインターフェース(CLI)を選択しました。

DynamoDB

テーブルの作成

以下で作成します。その他はデフォルトです。

  • テーブル名:TestJsonTable1
  • パーテーションキー:id
  • ソートキー:date

補足:予約語について

ソートキーで指定するdate予約語です。

DynamoDB の予約語 - Amazon DynamoDB

もし、AWSCLIで取得する場合は#をつけて実行する必要があるようです。
今回作成するLambda関数(Python)ではqueryメソッドを使用しますが、書式は変更しなくても取得出来ました。

DynamoDB の式の属性名 - Amazon DynamoDB

データの追加

pythonコードでjsonファイルを読み込み、テーブルに追加します。 エラーにならなければ"Data written to table successfully."が表示されます。

追加したデータはテーブル > 名前 > 項目の検索から確認できます。
例えば、クエリ、id:camera2date:次の値/2023-04-01および2023-04-2で実行すれば条件に応じたデータを表示できます。

テストデータ(test_data.json)を作成するコード

注意点
  • テストデータは正確ではありません。あくまでサンプルです。
  • データとしては特定のカメラで検出したPoseNetの骨格点情報を持つ日時データ(json)を想定しています。本来は検出時間間隔は短いのですが、サンプルのため30分間隔にしています。
  • skeletal_pointsは都合により検出時間で共通としています。
create_json_file.py
import json
import random
from datetime import datetime, timedelta

# 初期データ
skeletal_points = '[{"key_point": "2", "key_points": [{"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}]}, {"key_point": "3", "key_points": [{"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}, {"prob": "83.89", "x": "464", "y": "115"}]}]'
start_time = datetime(2023, 4, 1)
end_time = datetime(2023, 4, 5)
time_step = timedelta(minutes=30)

# 結果を格納するリスト
results = []

# 指定された時間範囲でループ
while start_time <= end_time:
    result = {
        "detected_date_time": start_time.strftime("%Y-%m-%dT%H:%M:%S.000"),
        "date": start_time.strftime("%Y-%m-%dT%H:%M:%S.000"),
        "detected_status": random.choice(["fallen", "normal"]),
        "id": random.choice(["camera1", "camera2"]),
        "skeletal_points": skeletal_points,
        "num_of_people": str(random.randint(0, 5)),
    }
    results.append(result)
    start_time += time_step

# JSONファイルに保存

with open("./incert_files/test_data.json", "w") as f:
    json.dump({"result": results}, f, indent=2)

test_data.jsonを書き込むコード

incert_data_json.py
import json
import boto3

# DynamoDBオブジェクトを取得
dynamodb = boto3.resource(
    "dynamodb",
    endpoint_url="https://dynamodb.ap-northeast-1.amazonaws.com",  # DynamoDBのエンドポイントURL
)

# テーブル名を定義
table_name = "TestJsonTable1"

# テーブルオブジェクトを取得
table = dynamodb.Table(table_name)

file_name = "./incert_files/test_data.json"

# JSONファイルからデータを読み込む
with open(file_name, "r") as f:
    data = json.load(f)

# データをテーブルに書き込む
for item in data["result"]:
    table.put_item(Item=item)

print("Data written to table successfully.")

API Gateway

GETメソッド 経由でLambda関数を実行するため、API GatewayAPIを作成します。

API作成

REST API

  • 新しいAPI
  • API名:TestJsonTable1_API1
  • APIエンドポイント:リージョン

メソッドを作成

  • メソッドタイプ: GET
  • 統合タイプ:Lambda 関数
  • Lambdaプロキシ:オフ
  • Lambda関数:後述するLambda関数のARNを指定

メソッドリクエストの設定

URL クエリ文字列パラメータ

メソッドリクエストを編集 > URL クエリ文字列パラメータ

  • id:必須(True)
  • start_date:必須(False)
  • end_date:必須(False)

統合リクエストの設定

マッピングテンプレート

{
  "id": "$input.params('id')",
  "start_date": "$input.params('start_date')",
  "end_date": "$input.params('end_date')"
}
マッピングテンプレートを設定する理由

URLクエリのみ設定すると以下のエラーになりました。

{'errorMessage': "'id'", 'errorType': 'KeyError', 'requestId': '[割愛]', 'stackTrace': ['  File "/var/task/lambda_function.py", line 17, in lambda_handler\n    id = event[\'id\']\n']}

chatgptで確認(2023/11/05時点)するとGETリクエストで指定したパラメータはLambda関数ではイベントオブジェクトでは参照できないようです。

これはエラーメッセージ'errorMessage': "'id'", 'errorType': 'KeyError'は、Pythonの辞書(この場合はevent)から存在しないキー(この場合は'id')を取得したことによるエラーです。

API Gateway経由でLambda関数を呼び出すとき、API GatewayはHTTPリクエストを特定の形式のイベントオブジェクトに変換します。このイベントオブジェクトは、Lambda関数のeventパラメータとして渡されます。

しかし、このイベントオブジェクトは、直接Lambda関数をテストするときに使用するイベントオブジェクトとは形式が異なる場合があります。そのため、Lambda関数がevent['id']を期待している場合でも、API Gatewayから渡されるイベントオブジェクトには'id'キーが含まれていない可能性があります。

この問題を解決するためには、API Gatewayの統合リクエストのマッピングテンプレートを設定して、HTTPリクエストから適切な形式のイベントオブジェクトを作成する必要があります。具体的には、マッピングテンプレートでHTTPリクエストのクエリパラメータ(この場合はid、start_date、end_date)をイベントオブジェクトの対応するキーにマッピングします。

これにより、Lambda関数はAPI Gatewayから期待する形式のイベントオブジェクトを受け取り、'id'キーを正しく取得できるようになります。

Lambda

GETリクエストのパラメータを元にDynamoDBから取得するクエリを設定、実行するLambda関数を作成します。

関数の作成

アーキテクチャではx86_64arm64を指定できますが、デフォルトで選択されていたx86_64を指定しました。
下記記事を見る限りは、処理速度、コスト面でarm64を選択するのが良さそうです。

参考記事

Lambdaのポリシー変更(追加)

IAM > アクセス管理 > ロール > Lambdaのロール名
dynamodbにアクセスするため、AmazonDynamoDBFullAccessを追加する
デフォルトではCloudWatchのログ出力するAWSLambdaBasicExecutionRoleが設定されている。

レイヤーの追加

pandasを使用するためPython 3.11版のarnを指定して追加します。

参考記事: [AWS]ARNとは?

pandasのarn情報

arnとして以下を指定します。

arn:aws:lambda:ap-northeast-1:336392948345:layer:AWSSDKPandas-Python311:2

参考情報: AWS Lambda Managed Layers — AWS SDK for pandas 3.4.2 documentation

Lambda関数作成

関数 > 関数名 > コード

import boto3
import pandas as pd
from boto3.dynamodb.conditions import Key

def lambda_handler(event, context):
    dynamodb = boto3.resource(
        "dynamodb",
        region_name="ap-northeast-1",  # 東京リージョン
        endpoint_url="https://dynamodb.ap-northeast-1.amazonaws.com",  # DynamoDBのエンドポイントURL
    )
    table = dynamodb.Table('TestJsonTable1')

    # print文を入れるとCloudWatchにログ出力できる
    # print(event) 

    id = event['id']
    start_date = event.get('start_date')
    end_date = event.get('end_date')

    if start_date and end_date:
        response = table.query(
            KeyConditionExpression=Key('id').eq(id) & Key('date').between(start_date, end_date)
        )
    else:
        response = table.query(
            KeyConditionExpression=Key('id').eq(id)
        )

    # 'result'キーでラップして返す
    return {"result": response['Items']}

タイムアウト時間の設定

実行結果次第でタイムアウト時間を伸ばす場合は以下で変更します。
関数 > 関数名 > 設定 > 一般設定 > 編集 > タイムアウト(変更) > 保存
3秒から30秒に変更しました。

テスト

Lambda関数が期待通り動作するかテストデータを使用して動作確認します。
ログから期待通り出力できていればOKです。

イベントJSON

{
  "id": "camera1",
  "start_date": "2023-04-01T00:00:00.000",
  "end_date": "2023-04-05T00:00:00.000"
}

実行結果

{
  "result": [
    {
      "detected_date_time": "2023-04-01T00:00:00.000",
      "date": "2023-04-01T00:00:00.000",
      "detected_status": "normal",
      "id": "camera1",
      "skeletal_points": "[{\"key_point\": \"2\", \"key_points\": [{\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}]}, {\"key_point\": \"3\", \"key_points\": [{\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}]}]",
      "num_of_people": "0"
    },
    ...
    {
      "detected_date_time": "2023-04-05T00:00:00.000",
      "date": "2023-04-05T00:00:00.000",
      "detected_status": "fallen",
      "id": "camera1",
      "skeletal_points": "[{\"key_point\": \"2\", \"key_points\": [{\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}]}, {\"key_point\": \"3\", \"key_points\": [{\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}, {\"prob\": \"83.89\", \"x\": \"464\", \"y\": \"115\"}]}]",
      "num_of_people": "0"
    }
  ]
}

リクエスト関数

ここまでで、DynamoDB,API Gateway, Lambda関数を作成し、設定することができたのでローカル環境からデータを取得できるか確認します。

動作確認用にrequestモジュールを使用してGETリクエストを送信するコードを作成します。受信したjsonデータはpandas / dataframeに変換して保存します。

事前準備

  • ローカルからAWSにアクセスするため、AWS認証情報を環境変数に設定します。詳細はAWSCLIを参照してください。

  • API GatewayではIAM認証を設定しているため、requests-aws4authをインストールしてください。AWS SigV4 による署名付きリクエストを送信できるようにします。

参考記事

request_api.py
import requests
from requests_aws4auth import AWS4Auth
from typing import Optional
import pandas as pd
import boto3

# AWS認証情報取得
session = boto3.Session()
credentials = session.get_credentials()
aws_access_key_id = credentials.access_key
aws_secret_access_key = credentials.secret_key
region_name = session.region_name
# 「API > ステージ > URLを呼び出す 」より参照
api_endpoint = "ステージ込みのエンドポイントを指定する"

# AWS4Authオブジェクトを作成
auth = AWS4Auth(aws_access_key_id, aws_secret_access_key, region_name, "execute-api")

def get_req(
    id: str,
    columns: list,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
):
    # リクエストを作成
    url = f"{api_endpoint}?id={id}"
    if start_date is not None:
        url += f"&start_date={start_date}"
    if end_date is not None:
        url += f"&end_date={end_date}"
    response = requests.get(url, auth=auth)

    # レスポンスを表示
    data = response.json()

    new_data = [[item[column] for column in columns] for item in data["result"]]

    # new_dataは上記で作成したリスト
    df = pd.DataFrame(new_data, columns=columns)
    return df


if __name__ == "__main__":
    columns = ["id", "date", "detected_status", "num_of_people","skeletal_points"]
    df = get_req("camera1", columns, "2023-04-01", "2023-04-02")
    print(df)
    #df = get_req("camera1", columns)

実行結果

指定範囲(日付)とcolumnsのリストに対応したDataframeオブジェクトを作成できています。

         id                 date detected_status num_of_people                                    skeletal_points
0   camera1  2023-04-01T00:00:00.000          normal             0  [{"key_point": "2", "key_points": [{"prob": "8...
1   camera1  2023-04-01T01:30:00.000          fallen             1  [{"key_point": "2", "key_points": [{"prob": "8...
2   camera1  2023-04-01T02:00:00.000          fallen             2  [{"key_point": "2", "key_points": [{"prob": "8...
3   camera1  2023-04-01T04:00:00.000          fallen             0  [{"key_point": "2", "key_points": [{"prob": "8...
4   camera1  2023-04-01T05:00:00.000          normal             4  [{"key_point": "2", "key_points": [{"prob": "8...
5   camera1  2023-04-01T06:30:00.000          fallen             0  [{"key_point": "2", "key_points": [{"prob": "8...
6   camera1  2023-04-01T08:00:00.000          fallen             0  [{"key_point": "2", "key_points": [{"prob": "8...
7   camera1  2023-04-01T09:30:00.000          fallen             5  [{"key_point": "2", "key_points": [{"prob": "8...
8   camera1  2023-04-01T10:00:00.000          normal             2  [{"key_point": "2", "key_points": [{"prob": "8...
9   camera1  2023-04-01T10:30:00.000          fallen             2  [{"key_point": "2", "key_points": [{"prob": "8...
10  camera1  2023-04-01T11:00:00.000          fallen             3  [{"key_point": "2", "key_points": [{"prob": "8...
11  camera1  2023-04-01T13:30:00.000          normal             3  [{"key_point": "2", "key_points": [{"prob": "8...
12  camera1  2023-04-01T15:00:00.000          normal             3  [{"key_point": "2", "key_points": [{"prob": "8...
13  camera1  2023-04-01T16:00:00.000          normal             1  [{"key_point": "2", "key_points": [{"prob": "8...
14  camera1  2023-04-01T17:00:00.000          fallen             5  [{"key_point": "2", "key_points": [{"prob": "8...
15  camera1  2023-04-01T18:00:00.000          fallen             5  [{"key_point": "2", "key_points": [{"prob": "8...
16  camera1  2023-04-01T19:30:00.000          fallen             4  [{"key_point": "2", "key_points": [{"prob": "8...
17  camera1  2023-04-01T21:00:00.000          fallen             2  [{"key_point": "2", "key_points": [{"prob": "8...
18  camera1  2023-04-01T23:30:00.000          normal             4  [{"key_point": "2", "key_points": [{"prob": "8...

まとめ

API Gateway + Lambda + DynamoDB構成でGETリクエストでDBのデータを取得して、DataFrameを作成する方法について紹介しました。
実際にサービスを使うことで触りの部分は理解できました。ただ、認証やネットワーク設定はわからない点が多いので、今後は本やドキュメントを見ながら理解を深めていきたいと思います。

以上です。