2026年7月9日

2026年7月9日

AWS Lambda + API Gatewayの設定方法|HTTP APIで作るWordPress用フォーム送信エンドポイント

Lambda 関数を Web から呼び出せるようにするには、API Gateway でエンドポイント(URL)を作り、Lambda と「プロキシ統合」でつなぎます。この記事では、WordPress のお問い合わせフォームから送信内容を受け取る API を例に、HTTP API の作成、ルートと統合、Lambda への呼び出し許可、CORS の設定、WordPress 側からの呼び出し方までを順に説明します。手順を終えると、ブラウザから送った JSON を Lambda で検証して結果を返す API が動く状態になります。

この記事は AWS ドキュメントの内容(2026年10月現在)をもとに説明していますが、API Gateway の種類ごとの機能差やコンソールの表記は更新されることがあります。Lambda 関数そのものの作り方(実行ロールやログの確認)は、別記事「AWS LambdaでServerless関数を作成する方法」で扱っているので、この記事では API として公開する部分に絞ります。

HTTP APIとREST APIのどちらを選ぶか

API Gateway には、主に HTTP API と REST API の2種類があります(ほかに WebSocket API があります)。

  • HTTP API: 構成が単純で、Lambda とつなぐだけの用途に向いています。CORS や JWT 認証(Amazon Cognito など)を標準で設定できます。
  • REST API: API キーと使用量プラン、リクエストの検証、AWS WAF との直接の連携など、機能が多い代わりに設定項目も多くなります。

フォーム送信や小さなデータ取得のように「Lambda を1つ呼ぶだけ」なら、HTTP API から始めるのが分かりやすい選択です。WAF を API Gateway に直接付けたい、API キーで利用者ごとに上限を管理したい、といった要件があるなら REST API を検討してください。どちらが対応しているかは更新で変わる可能性があるので、要件に関わる機能は最新のドキュメントで確認しましょう。

なお、Lambda には API Gateway を使わずに関数へ直接 URL を割り当てる「関数 URL」という機能もあります。ルートを分けない、細かい制御が不要という場合は、こちらのほうが簡単なこともあります。

手順1:フォームを受け取るLambda関数を用意する

HTTP API の Lambda プロキシ統合(ペイロード形式 2.0)では、リクエストの内容が event に入って関数へ渡されます。本文は event["body"] に文字列で入り、Base64 で符号化されている場合は event["isBase64Encoded"] が true になります。関数は statusCode、headers、body を持つ辞書を返します。

# lambda_function.py(wp-form-handler)
import base64
import json
import re

MAX_BODY = 10000
EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")


def response(status, payload):
    return {
        "statusCode": status,
        "headers": {"Content-Type": "application/json; charset=utf-8"},
        "body": json.dumps(payload, ensure_ascii=False),
    }


def lambda_handler(event, context):
    body = event.get("body") or ""
    if event.get("isBase64Encoded"):
        body = base64.b64decode(body).decode("utf-8")
    if len(body) > MAX_BODY:
        return response(413, {"error": "payload too large"})

    try:
        data = json.loads(body)
    except json.JSONDecodeError:
        return response(400, {"error": "invalid json"})
    if not isinstance(data, dict):
        return response(400, {"error": "invalid json"})

    name = str(data.get("name", "")).strip()
    email = str(data.get("email", "")).strip()
    message = str(data.get("message", "")).strip()

    if not name or len(name) > 100:
        return response(400, {"error": "invalid name"})
    if not EMAIL_RE.match(email) or len(email) > 254:
        return response(400, {"error": "invalid email"})
    if not message or len(message) > 2000:
        return response(400, {"error": "invalid message"})

    # ここで Amazon SES での通知や DynamoDB への保存を行う。
    # 氏名・メールアドレス・本文などの個人情報はログに出さない。
    print(json.dumps({"event": "contact_received", "request_id": context.aws_request_id}))
    return response(200, {"ok": True})

外部から誰でも呼べる API なので、入力はすべて信用せず、型と長さを検証してから使います。ログには受付の記録だけを残し、送信内容そのものを出力しないようにしてください。お問い合わせの内容は個人情報に当たるため、保存先・保存期間・利用目的をサイトのプライバシーポリシーに記載しておく必要があります。

手順2:HTTP APIを作成し、ルートと統合を設定する

コンソールでは、API Gateway の画面から HTTP API の作成を選び、統合に Lambda 関数を指定し、ルートとして POST /contact を設定します。ステージは自動デプロイが有効な $default を使うと、変更がすぐ反映されて扱いやすくなります。

CLI で作る場合は、API・統合・ルート・ステージを順に作ります。各コマンドが返す ID を次のコマンドで使います。

# 1. API の作成(CORS もここで設定)
aws apigatewayv2 create-api \
  --name wp-form-api \
  --protocol-type HTTP \
  --cors-configuration '{"AllowOrigins":["https://example.com"],"AllowMethods":["POST"],"AllowHeaders":["content-type"],"MaxAge":600}'

# 2. Lambda プロキシ統合の作成(返ってきた ApiId を使う)
aws apigatewayv2 create-integration \
  --api-id abcdef1234 \
  --integration-type AWS_PROXY \
  --integration-uri arn:aws:lambda:ap-northeast-1:123456789012:function:wp-form-handler \
  --payload-format-version 2.0

# 3. ルートの作成(返ってきた IntegrationId を使う)
aws apigatewayv2 create-route \
  --api-id abcdef1234 \
  --route-key "POST /contact" \
  --target integrations/xyz7890

# 4. 自動デプロイのステージを作成
aws apigatewayv2 create-stage \
  --api-id abcdef1234 \
  --stage-name '$default' \
  --auto-deploy

$default ステージを使った場合、エンドポイントは https://abcdef1234.execute-api.ap-northeast-1.amazonaws.com/contact の形になります。独自ドメインで公開したい場合は、API Gateway のカスタムドメイン名と ACM の証明書を組み合わせて設定します。

手順3:API GatewayにLambdaの呼び出しを許可する

CLI で統合を作った場合、API Gateway が Lambda を呼び出す許可(リソースベースポリシー)を別途付ける必要があります。これを忘れると、API を呼んだときに 500 の Internal Server Error が返り、Lambda のログには何も出ない、という分かりにくい症状になります。

aws lambda add-permission \
  --function-name wp-form-handler \
  --statement-id apigw-wp-form-api \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:ap-northeast-1:123456789012:abcdef1234/*/*/contact"

--source-arn で API とルートを限定しておくと、ほかの API から関数を呼ばれることを防げます。コンソールから統合を作った場合は、この許可が自動で追加されることが多いので、Lambda の「設定」にあるアクセス権限の画面で重複していないか確認してください。

手順4:CORSとスロットリングを設定する

WordPress のページ(https://example.com)から別ドメインの API(execute-api.amazonaws.com)を呼ぶため、ブラウザは CORS の確認を行います。Content-Type: application/json で送る場合は、本番のリクエストの前にプリフライト(OPTIONS)が送られます。

HTTP API で CORS を設定しておくと、API Gateway がプリフライトに自動で応答し、レスポンスに CORS ヘッダーを付けます。このとき Lambda が返す CORS ヘッダーは無視されるとされているため、設定は API Gateway 側に一本化します。AllowOrigins には自分のサイトのオリジンだけを指定し、* は避けてください。ただし、CORS はブラウザに対する制限であり、curl などからの直接の呼び出しは防げません。

そこで、呼び出し回数の上限(スロットリング)も設定します。HTTP API ではステージやルートごとに、1秒あたりのリクエスト数とバースト数の上限を指定できます。上限を超えたリクエストには 429 が返り、Lambda は呼ばれません。スパム対策としては、これに加えて CAPTCHA サービスのトークンを Lambda 側で検証する方法がありますが、検証方法はサービスごとに異なるので、各サービスのドキュメントに従ってください。

手順5:WordPressから呼び出す

テーマやプラグインから JavaScript を読み込み、API の URL を渡します。子テーマの functions.php に書く例です。strategy 引数による defer 指定は WordPress 6.3 以降で使えます。

add_action( 'wp_enqueue_scripts', function () {
	if ( ! is_page( 'contact' ) ) {
		return;
	}
	wp_enqueue_script(
		'wp-form-api',
		get_stylesheet_directory_uri() . '/js/contact-api.js',
		array(),
		'1.0.0',
		array(
			'in_footer' => true,
			'strategy'  => 'defer',
		)
	);
	wp_add_inline_script(
		'wp-form-api',
		'window.wpFormApi = ' . wp_json_encode(
			array( 'endpoint' => 'https://abcdef1234.execute-api.ap-northeast-1.amazonaws.com/contact' )
		) . ';',
		'before'
	);
} );
// js/contact-api.js
document.addEventListener('DOMContentLoaded', () => {
  const form = document.querySelector('#contact-form');
  if (!form) return;
  const status = form.querySelector('.form-status');

  form.addEventListener('submit', async (e) => {
    e.preventDefault();
    const data = Object.fromEntries(new FormData(form));
    try {
      const res = await fetch(window.wpFormApi.endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
      status.textContent = res.ok ? '送信しました。' : '送信できませんでした。入力内容を確認してください。';
    } catch (err) {
      status.textContent = '通信エラーが発生しました。時間をおいて再度お試しください。';
    }
  });
});

結果の表示に innerHTML ではなく textContent を使っているのは、API の応答に想定外の文字列が含まれても HTML として解釈されないようにするためです。

動作確認とつまずきやすい点

まず curl で API 単体の動作を確認します。

curl -i -X POST https://abcdef1234.execute-api.ap-northeast-1.amazonaws.com/contact \
  -H "Content-Type: application/json" \
  -d '{"name":"テスト","email":"test@example.com","message":"動作確認です"}'

200 と {"ok": true} が返れば成功です。うまくいかない場合は、よくある順に次を確認します。

  1. 500 が返り、Lambda のログが無い: 手順3の呼び出し許可が無いか、--source-arn の API ID が違います。
  2. 404 Not Found: ルートキー(POST /contact)とリクエストのメソッド・パスが一致しているか、ステージがデプロイされているかを確認します。
  3. ブラウザだけ失敗し、curl では成功する: CORS の AllowOrigins と実際のサイトのオリジン(https:// の有無、www の有無)が一致しているかを、開発者ツールのコンソールで確認します。
  4. 502 が返る: Lambda の戻り値の形式が崩れているか、関数内で例外が起きています。CloudWatch Logs でエラー内容を確認します。

まとめ

  • Lambda を1つ呼ぶだけなら HTTP API、WAF の直接連携や API キーが必要なら REST API を検討する。
  • CLI では API・統合・ルート・ステージを順に作り、lambda add-permission で呼び出しを許可する。
  • CORS は API Gateway 側で自分のオリジンだけを許可し、スロットリングで呼び出し回数に上限を設ける。
  • 公開 API では入力を検証し、個人情報をログに残さず、プライバシーポリシーに取り扱いを書く。
  • WordPress 側は wp_enqueue_script と wp_add_inline_script で URL を渡し、結果は textContent で表示する。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲