小ネタ – AWS Lambda を使って Amazon Aurora Serverless からデータを配列で取得する

こんにちは、広野です。

サーバーレスアプリを開発していると、基本データベースは Amazon DynamoDB などの NoSQL を使用するのが王道なのですが、NoSQLでは対応しきれない要件のときにはやはり RDBMS を使用する局面もあります。

そんなとき、サーバーレスの RDBMS サービスである Amazon Aurora Serverless を積極的に使っていきたいのですが、AWS Lambda でデータを取得しようとするとデフォルトのままでは扱いづらい特殊なデータフォーマットになってしまいます。

この度、データフォーマットをシンプルな配列に加工する仕組みを検証しましたので紹介します。

やりたいこと

  • Amazon Aurora Serverless から AWS Lambda でデータを取得する。
  • データの取得には Data API を使用する。※Data API については以下リンクを参照
  • 最終的なデータの取得形式は、配列にしたい。
Aurora Serverless の Data API の使用 - Amazon Aurora
Aurora Serverless の Data API を使用すると、 Aurora Serverless DB クラスターへのウェブサービスインターフェイスを操作できます。Data API は、DB クラスターへの永続的な接続を必要としません。代わりに、セキュア HTTP エンドポイントおよび AWS SDK との...

実装方法

サンプルデータ

DB内には以下のようなテーブルがあるとしましょう。ここでは、このデータを全て取得してくるSQLを使用する想定です。

sampletable

id name number (数値型)
A001 いか 10
A002 たこ 20
B001 すし 30

加工前

AWS Lambda 関数 (Python)

import boto3
rds_client = boto3.client('rds-data')

def lambda_handler(event, context):
  # Database settings
  database_name = 'sampledatabase'
  db_cluster_arn = 'arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:cluster:samplecluster'
  db_credentials_secrets_store_arn = 'arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:rds-db-credentials/cluster-XXXXXXXXXXXXXXXXXXXXXXXXXX/xxxxxxxxxxxx'
  
  # Executing SQL
  def execute_statement(sql):
    response = rds_client.execute_statement(
      secretArn=db_credentials_secrets_store_arn,
      database=database_name,
      resourceArn=db_cluster_arn,
      sql=sql
    )
    return response

  # SQL実行結果をdataに格納
  data = execute_statement('select * from sampletable')
  # データをそのまま返す
  return data

結果データ

こんな感じの JSON データが返ってきます。

data[‘records’] にクエリーの結果データが格納されているのですが、データ型によって stringValue や longValue などといったキーが入った JSON データフォーマットになっており、非常に扱いづらいです。また、テーブルの列名は返ってきません。

{
  "ResponseMetadata": {
    "RequestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "x-amzn-requestid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "content-type": "application/json",
      "content-length": "xxx",
      "date": "Mon, 21 Mar 2022 00:00:00 GMT"
    },
    "RetryAttempts": 0
  },
  "numberOfRecordsUpdated": 0,
  "records": [
    [
      {
        "stringValue": "A001"
      },
      {
        "stringValue": "いか"
      },
      {
        "longValue": 10
      }
    ],
    [
      {
        "stringValue": "A002"
      },
      {
        "stringValue": "たこ"
      },
      {
        "longValue": 20
      }
    ],
    [
      {
        "stringValue": "B001"
      },
      {
        "stringValue": "すし"
      },
      {
        "longValue": 30
      }
    ]
  ]
}

これを、以下で加工します。

加工後

AWS Lambda 関数 (Python)

クエリー結果の data を加工する関数を追加し、return で返す前にフォーマットを変換しています。

import boto3
rds_client = boto3.client('rds-data')

def lambda_handler(event, context):
  # Database settings
  database_name = 'sampledatabase'
  db_cluster_arn = 'arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:cluster:samplecluster'
  db_credentials_secrets_store_arn = 'arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:rds-db-credentials/cluster-XXXXXXXXXXXXXXXXXXXXXXXXXX/xxxxxxxxxxxx'
  
  # Formatting query returned Field
  def formatField(field):
    return list(field.values())[0]
  # Formatting query returned Record
  def formatRecord(record):
    return [formatField(field) for field in record]
  # Formatting query returned Field
  def formatRecords(records):
    return [formatRecord(record) for record in records]
  # Executing SQL
  def execute_statement(sql):
    response = rds_client.execute_statement(
      secretArn=db_credentials_secrets_store_arn,
      database=database_name,
      resourceArn=db_cluster_arn,
      sql=sql
    )
    return response

  # SQL実行結果をdataに格納
  data = execute_statement('select * from sampletable')
  # 配列にフォーマットしたデータを返す
  return formatRecords(data['records'])

結果データ

スッキリしました!

これなら、アプリ側でも比較的扱いやすいです。連想配列ではないので、アプリで使用するときには列の並び順をきっちり押さえておく必要があります。

[
  [
    "A001",
    "いか",
    10
  ],
  [
    "A002",
    "たこ",
    20
  ],
  [
    "B001",
    "すし",
    30
  ]
]

IAM ロール

AWS Lambda 関数に付与する IAM ロールは、データを読み書きするのであればマネージドのRDSフルポリシーを付けておけばとりあえず動きますが、用途が明確になっているようでしたら Action や Resource 等をさらに制限しましょう。

マネージドポリシー

  • arn:aws:iam::aws:policy/AmazonRDSDataFullAccess
  • arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

まとめ

いかがでしたでしょうか?

エラー処理、ページネーション処理までは言及していないので実運用には物足りない内容かと思いますが、あくまでデータフォーマットの加工 TIPS としてお役に立てれば幸いです。

Amazon Aurora Serverless は今時点では RDS Proxy も未サポートなので、膨大なクエリーを受けるような環境では耐えられないかもしれません。比較的小規模で、重要性の低いユースケースであれば迷いなくオススメします。

タイトルとURLをコピーしました