Webhookリプレイは、上流プロバイダーにイベントを再配信させることなく、以前捕捉したHTTPコールバックをローカルハンドラへ再送します。Stripeの課金、GitHubのプッシュ、Twilioのメッセージを再発生させる代わりに、リクエスト履歴からまったく同じリクエスト(ヘッダーもボディも全部)をリプレイします。
なぜWebhookリプレイが重要なのか
Webhookのデバッグはたいてい面倒なループになります。イベントを発生させ、配信を確認し、バグを見つけ、コードを直し、また発生させる。上流イベントの再発生は遅く、ノイズが多く、ときに不可能です(一度きりの課金イベント、削除済みリソース、レート制限のあるテストAPIなど)。
リプレイはそのループを縮めます。一度捕捉し、ハンドラを直し、通るまで同じペイロードをリプレイする。外部プロバイダーに一切触れずに済みます。
Webhookリプレイの仕組み
- コールバックがトンネルURLに届き、ローカルアプリへ転送されます。
- トンネルツールがリクエスト全体(メソッド、パス、ヘッダー、ボディ)を捕捉します。
- 捕捉したリクエストを見て、ハンドラのコードを修正します。
- 捕捉したリクエストをワンアクションでローカルエンドポイントへリプレイします。
- ハンドラが正しいレスポンスを返すまで繰り返します。
このワークフローには、単なるトラフィック転送ではなく、リクエスト捕捉を内蔵したlocalhostトンネルが必要です。
Webhookリプレイのユースケース
ハンドラ開発
Webhookハンドラを反復的に構築・テストします。パースロジックを磨きながら、同じStripeのcheckout.session.completedイベントを10回リプレイします。
冪等性テスト
プロバイダーはリトライ時に重複イベントを配信します。同じペイロードを何度もリプレイして、二重課金や重複レコードを生まずに重複を安全に処理できることを確認します。
署名検証のデバッグ
署名チェックが失敗したら、ヘッダーをそのままにした元のリクエストをリプレイし、問題が検証ロジックにあるのかペイロードのパースにあるのかを切り分けます。
リグレッションテスト
本番に近いテストイベントの捕捉済みリクエストを保存し、リファクタ後にリプレイして、デプロイ前に破壊的変更を検出します。
PortPreviewでのWebhookリプレイ
- アプリを起動し、
npx portpreview 3000を実行します。 - プロバイダーがトンネルURLへコールバックを送るよう設定します。
- テストイベントを発生させ、PortPreviewで捕捉したリクエストを確認します。
- ハンドラを修正し、捕捉したリクエストをリプレイします。
- プロバイダーを再発生させずに、レスポンスのステータスとボディを確認します。
PortPreviewは元のヘッダーを保持するため、リプレイ中もプロバイダーの署名検証が意味を保ちます。
リプレイ vs 再発生: どちらを使うか
- リプレイ: ハンドラのロジックバグ、ペイロードのパース、冪等性チェック、署名デバッグ。
- 再発生: プロバイダー側のイベント生成のテスト、Webhook登録の検証、ライブなプロバイダー状態とのエンドツーエンド統合。
プロバイダー別の設定は、StripeのWebhookローカルテスト、GitHubのWebhookローカルテスト、TwilioのWebhookローカルテストのガイドを参照してください。
Webhookリプレイのベストプラクティス
- 初回配信だけでなく、リプレイ時にも必ず署名を検証する。
- 同じイベントを複数回リプレイして重複配信をテストする。
- リグレッションチェックのため、featureブランチ中はリクエスト履歴を保持する。
- リプレイしたイベントが本番データに影響しないよう、テストモードの認証情報を使う。
Webhookの捕捉とリプレイをトンネルワークフローに組み込むには、PortPreviewのウェイトリストに登録してください。