このレッスンのロックを解除するには、まず「レッスン4:サービス間のデータ変換とルーティング」を完了してください。前のレッスンに戻る

Webhookとは何か、なぜ重要なのか

ほとんどのAPI連携はプル型です。ワークフローがスケジュールで実行され、外部サービスを呼び出し、前回の確認以降に変更されたものを取得します。Webhookはそのモデルをひっくり返します。こちらが問い合わせる代わりに、外部サービスは何かが発生した瞬間に——決済完了、フォーム送信、リポジトリへの新しいコミットなど——データをこちらにプッシュしてきます。結果として、ポーリングのオーバーヘッドなしにほぼリアルタイムで反応できます。

n8nには組み込みのWebhookノードがあり、どんなワークフローでもHTTPエンドポイントに変換できます。そのエンドポイントがリクエストを受信すると、ワークフローが即座に起動します。このレッスンでは、その設定方法、受信ペイロードの処理方法、呼び出し元への適切なレスポンス返却方法について順を追って説明します。

ポーリングモデル(n8nがAPIを繰り返し呼び出す)とWebhookモデル(イベント発生時にAPIがn8nを一度だけ呼び出す)を比較するフローダイアグラム

Webhookノードの設定

Webhookノードをキャンバスにドラッグし、トリガー(最初のノード)として設定します。最初に構成する2つの設定は、HTTPメソッドとパスです。

HTTPメソッドはほぼ常にPOSTです。主要プラットフォームが送信してくるのはPOSTだからです。GETを使用するのは、サードパーティが明示的にそれを文書化している場合に限定してください(一部の検証ハンドシェイクではGETが使用されます)。

パスはこのワークフローを識別するユニークなスラッグです。n8nはデフォルトでUUIDを生成しますが、/stripe-eventsや/github-pushのような読みやすいものを設定することもできます。n8nが表示する完全なURLは次のようになります:

bash
https://your-n8n-instance.com/webhook/stripe-events

そのURLをサードパーティプラットフォームのWebhook設定——Stripeダッシュボード、GitHubリポジトリ設定、Typeform、その他利用しているサービス——に貼り付けます。

n8nはノードごとに2つのWebhook URLを提供します:テストURLと本番URLです。テストURLはエディターでワークフローを開いてリスニングしている間のみ有効です。本番URLはワークフローが保存され、有効化された状態でのみ有効です。本番の連携では、ベンダーにテストURLを絶対に渡さないでください——ブラウザのタブを閉じた瞬間に機能しなくなります。

ペイロードの受信と解析

Webhookが発火すると、受信データはWebhookノードの出力に格納されます。n8nはJSONボディを自動的に解析するため、Stripeがpayment_intent.succeededイベントを送信した場合、課金金額には後続のノードから次のように式でアクセスできます:

javascript
{{ $json.data.object.amount }}

フォームエンコードボディ(一部の古いサービスはContent-Type: application/x-www-form-urlencodedで送信します)の場合も、n8nはそれを自動的に同じ$jsonオブジェクトに解析します。

ヘッダーも利用可能ですが、これは署名検証において重要です。Stripe、GitHub、その他ほとんどの真面目なプラットフォームは、HMACシークレットでWebhookペイロードに署名し、リクエストが本当にそれらのサービスから来たものであるかを確認できるようにしています。n8nでは、Codeノード内で署名ヘッダーを読み取り、検証することができます:

javascript
const crypto = require('crypto');
const secret = 'your_webhook_secret';
const payload = $input.first().binary?.data
? Buffer.from($input.first().binary.data, 'base64').toString()
: JSON.stringify($input.first().json);
const signature = $input.first().headers['x-hub-signature-256'];
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
if (signature !== expected) {
throw new Error('Invalid webhook signature');
}
return $input.all();

メール送信、レコード変更、ユーザーへの課金など、何か機密性の高い処理を引き起こす本番ワークフローでは、必ず署名を検証してください。

Webhookノードがリクエストを受信し、署名チェック用のCodeノードに渡し、その後処理ノードまたはエラーノードに分岐するブロック図

呼び出し元へのレスポンス返却

一部のプラットフォームは、デフォルトの200 OKだけでなく、特定のHTTPレスポンスを必要とします。Stripeは数秒以内に200を期待しており、そうでなければリトライします。GitHubは200を期待します。Typeformやカスタム内部サービスなどの一部のシステムでは、受信確認のJSONボディが返されることを求めます。

Webhookノードの設定で、レスポンスタイプを「Last Node」に設定します。これでワークフローの最後のノードが、何が返送されるかを制御します。チェーンの最後でRespond to Webhookノードと組み合わせ、以下のように設定します:

json
{
"statusCode": 200,
"body": { "received": true, "id": "={{ $json.id }}" }
}

ワークフローが重い処理——データベース書き込み、メール送信、他のAPI呼び出し——を行い、それでも高速にレスポンスを返す必要がある場合は、Webhookノードでレスポンスタイプとして「Immediately」を使用します。n8nはすぐに200を返し、バックグラウンドでワークフローの残りを実行し続けます。トレードオフは動的なレスポンスボディを送信できないことですが、呼び出し元がタイムアウトすることはありません。

避けるべき一般的なミス

本番環境でテストURLを使用することが最も頻繁なミスです。エディターを閉じた瞬間にワークフローは沈黙し、誰もイベントが失われていることに気づきません。

リトライを処理しないことも別の落とし穴です。Stripeは失敗したWebhookを最大72時間リトライします。ワークフローに冪等性がない——つまり、同じイベントに対して2回実行するとレコードが重複したり、二重課金が発生する——場合、何らかの書き込みを行う前に、指定されたイベントIDをすでに処理済みかどうかを確認する必要があります。

レスポンスタイムアウトを無視すると、静かな失敗が発生します。ワークフローに30秒かかり、呼び出し元が5秒でレスポンスを期待している場合、配信を失敗としてマークし、リトライします。ワークフローは最終的に成功するにもかかわらずです。即座にレスポンスを返すか、処理パスを最適化してください。

まとめ

Webhookにより、サードパーティサービスはスケジュールされたポーリングを必要とせずに、リアルタイムでn8nにイベントをプッシュできます。パスとHTTPメソッドを指定してWebhookノードを設定し、本番URLをベンダーの設定に貼り付け、$jsonを通じて下流のノードでペイロードにアクセスします。署名検証はスプーフィングされたリクエストから保護し、Respond to WebhookノードまたはImmediatelyモードが呼び出し元に返す内容を制御します。正しいURL、署名チェック、冪等性、レスポンスタイミングといった細部を正しく押さえることが、もろい連携と本番環境で確実に動作する連携を分けるのです。

レッスンの練習

レッスンのチェックポイント

学んだ内容を復習し、回答へのフィードバックを受けましょう。

0/7
01Webhookベースの連携とポーリングベースの連携の重要なアーキテクチャ上の違いは何ですか?
02n8nで、テストURLではなく本番Webhook URLを使用すべきなのはどのような場合ですか?
03サードパーティサービスがContent-Type: application/x-www-form-urlencodedでWebhookを送信しました。n8nはこのペイロードをどのように処理しますか?
04受信WebhookリクエストのHMAC署名を検証する目的は何ですか?
05受信ペイロードのフィールドを含むカスタムJSONボディで呼び出し元にレスポンスする必要があります。どのWebhookノードのレスポンスタイプを使用すべきですか?
06ワークフローがWebhook受信後に複数の低速なデータベース書き込みを行います。呼び出し元サービスは5秒後にタイムアウトします。呼び出し元が配信を失敗としてマークするのを防ぐための最適なレスポンスタイプは何ですか?
07エンドポイントが初回のリクエストでエラーを返したため、StripeがWebhookイベントをリトライします。あなたのワークフローには冪等性がありません。考えられる結果は何ですか?
回答済み · 0/7