メインコンテンツへ移動

サーバーレス実装

API Gateway + Lambda + DynamoDBで問い合わせAPIを作る流れ

問い合わせフォームをサーバーレスAPIで保存する流れを、フロントエンドからDynamoDB保存まで整理します。

公開日2026-06-07/更新日2026-08-20/著者AWS Cert Roadmap Lab
#API Gateway#Lambda#DynamoDB#Contact Form#Serverless

静的サイトでも、問い合わせフォームのようなユーザー入力は保存先が必要です。このサイトでは、API Gateway + Lambda + DynamoDBで問い合わせAPIを構成します。

結論

フロントエンドがPOST /contactを呼び、API GatewayがLambdaを起動し、Lambdaが入力値を検証してDynamoDBに保存します。

全体フロー

  1. ユーザーが問い合わせフォームに入力する
  2. フロントエンドで必須チェックとメール形式チェックを行う
  3. API GatewayのPOST /contactへJSONを送信する
  4. LambdaがリクエストBodyをパースする
  5. honeypotを確認する
  6. Lambda側でもバリデーションする
  7. DynamoDBへPutItemする
  8. 成功レスポンスを返す
  9. フロントエンドで完了メッセージを表示する

なぜフロントだけで検証しないのか

フロントエンドのチェックはユーザー体験をよくするためのものです。セキュリティ上は信用できません。

APIに直接リクエストされる可能性があるため、Lambda側でも必須項目、文字数、メール形式、honeypotを確認します。

DynamoDBに保存するデータ

保存する項目は、contactId、createdAt、name、email、subject、message、sourcePage、status、userAgentなどです。

ただし、CloudWatch Logsにはメールアドレス全文や本文全文を出しません。ログにはrequestId、contactId、エラー種別など、調査に必要な最小情報だけを出します。

CORSの扱い

本番では許可Originを本番ドメインに限定します。開発環境のlocalhostは開発時だけ許可します。

CORSを * にして本番運用するのは避けます。

この構成のメリット

  • EC2を使わない
  • サーバー管理が不要
  • 低頻度アクセスなら低コストにしやすい
  • AWS資格で学ぶ主要サービスを実装で使える
  • ポートフォリオで設計意図を説明しやすい

リリース後に確認する処理の記録

API を公開したら、正常な問い合わせを1件送信し、ブラウザの送信時刻、API Gateway のリクエスト、Lambda の request ID、DynamoDB に作られた contactId を順に照合します。この4点がつながれば、画面から保存先までの経路が実際に通っていることを確認できます。デプロイしたバージョンや環境名もログに含めると、古いLambdaや別環境のテーブルを見てしまう調査ミスを防げます。

失敗時も同じ順序で追います。API Gateway に到達していなければ、URL、HTTPメソッド、CORS、認可設定を確認します。Lambda に到達して 400 なら、検証で弾いた項目とクライアントが送った形式を照合します。500 なら、例外名、DynamoDB の AccessDenied、タイムアウト、テーブル名を環境変数から取得できているかを確認します。利用者へ返す本文には内部エラーを含めず、運用者だけが request ID を使って詳細を追えるようにします。

問い合わせ本文やメールアドレスをログへ複製すると、便利な調査記録が個人情報の保管場所にもなります。通常ログは contactId、文字数、検証結果、処理時間にとどめ、本文を確認する必要があるときはアクセス制御された保存先を参照します。ログ閲覧権限とDynamoDB読取り権限を分けると、障害対応に必要な人へ必要な範囲だけを渡せます。

運用開始後は、失敗率、重複送信、実行時間、ログ量を定期的に見直します。通知やログ保管の設定はアクセス量と調査要件で変わるため、固定の料金や保持日数を前提にせず、実際の利用状況とAWSコンソールの表示を確認して判断します。

設定変更は、API の URL、CORS の許可 Origin、テーブル名、実行ロールのいずれを変えたかも記録します。障害時に直近の変更と request ID を結び付けられれば、コード、インフラ、ブラウザ設定のどこから確認するかを早く決められます。

ブラウザから保存までの責務を分ける

問い合わせフォームでは、ブラウザが POST /contact に JSON を送信し、API Gateway が HTTP の入口になります。Lambda は受け取った本文を解析して入力を検証し、保存してよいデータだけを DynamoDB に PutItem します。成功時は 201 または 200、入力不備は 400、想定外の障害は 500 のように、クライアントが再試行や表示を判断できる応答を返します。

API Gateway HTTP API ではルートと統合の考え方を、Lambda と API Gateway の使用 ではイベントとレスポンスの形式を確認できます。最初から通知や管理画面を加えるのではなく、受信、検証、保存、追跡できる経路を一本通してから機能を増やすと、失敗地点を切り分けやすくなります。

ブラウザ側の必須入力チェックは利用者への早いフィードバックとして有効ですが、安全性の境界ではありません。開発者ツールや別クライアントからは回避できるため、Lambda で型、空文字、文字数、許可する値を必ず再検証します。本文全体を信用してそのまま保存・表示しないことが、入力値を扱うAPIの出発点です。

入力検証とCORSの実装境界

Lambda では event.body を安全に JSON として解析します。nameemailsubjectmessage の型と最大文字数を確認し、検証に失敗したら DynamoDB に書き込まず、たとえば INVALID_EMAILMESSAGE_TOO_LONG のようなエラーコードを 400 とともに返します。画面の文言は変えられても、API の分岐を安定させられます。

CORS は単に「ブラウザから呼べるようにする」設定ではありません。どの Origin の JavaScript に、どのメソッド・ヘッダーでアクセスを許可するかを決める境界です。本番の Origin を明示し、開発用の localhost は環境ごとに分けます。OPTIONS の preflight と実際の POST の両方で期待するヘッダーが返るかを確認し、認証情報を扱う構成で安易に * を使わないようにします。

ブラウザでは失敗するのに curl では成功する場合、Lambda の実装より先に CORS、許可 Origin、許可ヘッダー、ルートを確認します。Lambda のログが増えていなければ、関数内の入力検証を調べ続けても原因には到達しません。

DynamoDB保存と重複送信の扱い

保存レコードには、Lambda 側で発行する contactId、受信時刻、入力項目、処理状態を持たせます。クライアントの値を主キーとして信用せず、時刻は UTC の ISO 8601 形式にそろえると、後からログと保存データを照合しやすくなります。どの画面・処理で読むかを先に書き出し、必要なアクセスパターンに合わせてキーやインデックスを決めます。

送信ボタンを二度押しした場合だけでなく、通信切断後の再送でも同じ問い合わせが複数届くことがあります。画面では送信中にボタンを無効化し、API側では idempotency key を使って同じ送信を判定できる設計を検討します。最小構成でUI対策から始める場合も、API単体では重複を完全に防げない点を明示しておきます。

保存が成功しているのに重複が出たときは、request ID、contactId、idempotency key を比べます。同一実行内のバグか、別リクエストの再送かを区別できるためです。テーブルとキーの基本はAmazon DynamoDBとは?NoSQLを初心者向けに解説も参照してください。

IAM実行ロールを最小権限にする

Lambda の実行ロールには、対象 DynamoDB テーブルへの dynamodb:PutItem など、処理に必要な操作だけを付与します。ログ出力には CloudWatch Logs の書込み権限も必要ですが、保存権限と混同せず、対象 Resource と Action を分けて確認します。管理操作や全テーブルへの権限は、問い合わせを保存する関数には不要です。

AccessDenied が出たときに AdministratorAccess を付けて動かすのは、原因を隠し、権限を残す失敗につながります。CloudWatch Logs のエラーで不足した操作を確認し、IAM ポリシーの対象テーブル ARN と照合して最小の許可を追加します。CI のデプロイロールと Lambda 実行ロールも分離し、実行時に必要な権限だけを関数へ渡します。

ログとエラーレスポンスを運用に使う

ログには Lambda の request ID、アプリケーション側の contactId、ルート、ステータス、エラー分類を構造化して残します。問い合わせ本文、メールアドレス、Authorization ヘッダーを丸ごと記録すると、運用ログに個人情報や秘密情報が増えます。診断には文字数、必須項目の有無、エラーコードなど必要な情報を中心にします。

利用者へ返すエラーと運用ログは目的が異なります。入力不備は 400 と一般的な説明を返し、権限不足やコード例外は 500 として詳細をログだけで確認できるようにします。スタックトレースやテーブル名をレスポンスへ返さないことで、内部実装の露出を避けます。

ログの保持期間や取り込み量は、ワークロード、リージョン、設定で変わります。固定の料金や日数を前提にせず、調査に必要な期間、個人情報を含む可能性、障害の発見頻度を基準に設定を見直します。

失敗例から作る確認手順

確認用に、正常送信、必須項目不足、不正な JSON、DynamoDB 権限不足のケースを用意します。それぞれで期待するHTTPステータス、Lambdaのログ、DynamoDBへの保存有無を記録します。400500 を混ぜないことにより、利用者の入力ミスと運用障害を区別できます。

リリース後は、実際に1件送信して request ID からログを追い、保存先の contactId と一致することまで確認します。次の学習として、Amazon API Gatewayとは?HTTP APIを初心者向けに解説LambdaのログをCloudWatchで確認する方法 を読むと、HTTP境界と調査方法をつなげて理解できます。

関連用語

次に読む記事

次に学ぶ内容

ブログ記事だけでなく、AWS用語集・サービス比較・模擬問題・構成図を組み合わせると、資格知識と実装イメージをつなげて理解できます。