API Gateway + DynamoDB のみで JSON を受け取る

AWS

API Gateway で受け取ったデータをマッピングテンプレートで変換し、DynamoDB が理解できる形式にして直接投げ込みます。Lambda は使用しません。

AWS構成イメージ

AWS アイコンの構成図、一度くらい載せたくて作ったのはいいですが、何となくコレジャナイ感が。

CSP(Content-Security-Policy) のレポートを受け取る

ここは余談です。
今回は、CSP レポートを受け取るために環境を構築しました。

CSP とは、サイトのセキュリティポリシーを設定する機能で、XSS 軽減や Mixed Content 検出などに役立ちます。詳しくは Google 先生へ

CSP ではポリシー違反の発生時にブラウザから違反内容を報告させる機能があり、指定した URL に json 形式で POST されます。今回は違反報告を API Gateway + DynamoDB で受け取りました。

DynamoDB テーブル作成

まずは json の格納先として、DynamoDB のテーブルを作成します。プライマリキーを id 列として作成しました。

DynamoDBのテーブル作成

IAM ポリシー作成

DynamoDB にアクセスできる IAM ポリシーを作成します。今回は、Policy Generator で PutItem のみ許可しました。

DynamoDB用IAMポリシー

IAM ロール作成

API Gateway 用のロールを作成します。中身はデフォルト、名前は適当です。

API Gateway用のIAMロール作成

作成後に、先ほど用意した IAM ポリシーを追加でアタッチします。

IAMロールにポリシーをアタッチ

ここで作成した IAM ロールの ARN をメモしておきます。

API Gateway 作成

API Gateway を新規作成します。例によって名前は適当。

API Gatewayを新規作成

アクションメソッドの追加 から POST メソッドの処理を追加します。

API GatewayにPOSTメソッドを追加

以下のように設定して保存します。

  • 統合タイプ: AWS サービス
  • AWS リージョン: 使用するリージョン
  • AWS サービス: DynamoDB
  • HTTP メソッド: POST
  • アクション: PutItem
  • 実行ロール: メモした IAM ロールの ARN

API Gatewayのリクエスト設定

マッピングテンプレート作成

DynamoDB へ登録するために、リクエストの形式を変換します。

統合リクエスト を再度クリックします。

API Gatewayの設定画面

最下部にある 本文マッピングテンプレート を設定します。

  • リクエスト本文のパススルー: なし
  • Content-Type: application/json を追加

※今回は、CSP レポート受信のため application/csp-report も追加(設定内容は同一)

マッピングテンプレート設定

使用しているコードは以下の通りです。フォーマットは公式ドキュメント参照。

#set($inputRoot = $input.path('$'))
{
  "TableName": "<DynamoDB テーブル名>",
  "Item": { 
    "id": { 
      "S": "$context.requestId"
    },
    "body": {
      "S": "$inputRoot"
    }
  }
}

API Gateway が自動生成するリクエスト UUID ($context.requestId) を、そのまま DynamoDB の id カラムとして使用しています。
POST されてきた JSON は、$inputRoot に格納されています。

今回は body というカラム名で丸ごと突っ込んでいます。JSON から必要な属性だけを抜き出すこともできますが、それは後ほど。

テスト実行

POST メソッドの画面に戻り、左上の テスト ボタンをクリックします。

API Gatewayの設定画面

最下部に、任意のリクエスト内容を入力できます。ここでは、CSP レポートの例をそのまま入れてみます。

API Gatewayの設定機能

成功したようです。

API Gatewayのテスト結果

DynamoDB を確認してみると、無事に JSON が格納されていました……が、文字列として格納されるのがイケてないですね。対応は 応用編 で。

DynamoDBの格納結果

【注意点】
上記画像をよく見ると分かるのですが、テスト実行では $context.requestIdtest-invoke-request という固定文字列が入ります。
本来はここにランダムな ID が入るため問題ありませんが、テスト実行では毎回この値となるため、連続でテスト実行するとプライマリキー重複でエラーとなります。

API のデプロイ

動作確認が取れたのでデプロイします。ここからは通常の API Gateway と同じ手順です。

API Gatewayのアクションメニュー
API Gatewayをデプロイする

デプロイできました。

API Gatewayのデプロイ完了

ここで発行された URL に JSON を POST すると、先ほどの DynamoDB に格納されます。あとは思う存分データを投げつけましょう。

応用編

JSON の中で欲しい属性が定まっている場合は、例えば以下のように定義すると幸せになれます。

マッピングテンプレート

#set($inputRoot = $input.path('$'))
{
  "TableName": "csp-report",
  "Item": { 
    "id": {
      "S": "$context.requestId"
    },
    "document-uri": {
      "S": "$inputRoot.csp-report.document-uri"
    },
    "blocked-uri": {
      "S": "$inputRoot.csp-report.blocked-uri"
    }
  }
}

POST 内容
API Gatewayの設定機能

パースされた格納結果
DynamoDBにパースして格納される


以上です。ツッコミ等々ありましたら、ぜひコメント等よろしくお願いします。