WebhookとAPIの違い:取りに行くか、送ってもらうか
WebhookとAPIの違い
WebhookとAPIの違い:プッシュとプル、署名、リトライ | We.Inc
WebhookとAPIの違いを、比較表、ポーリングとプッシュのトレードオフ、ブラウザー上で動くHMAC署名チェッカー、リトライの扱い、冪等な受信側コードで解説します。
API呼び出しでは、自分のコードが好きなときに別のサービスへデータを要求します。これがプルです。Webhookでは、何かが起きた瞬間にサービスが自分のURLへHTTP POSTを送ってきます。これがプッシュです。多くの連携では両方を使います。Webhookで変更をすばやく知り、API呼び出しで最新の完全なレコードを取得します。
APIリクエストとWebhookの比較
- APIリクエスト(プル)
- Webhook(プッシュ)
- タイミング
- 要求したとき、またはポーリングのタイマーで
- イベントの直後
- 必要なもの
- APIキーとクライアント
- 公開されたHTTPSエンドポイント
- 送信元の証明
- 提供元が自分のキーを確認
- 自分が提供元の署名を確認
- 失敗したとき
- 自分がエラーを見てリトライ
- 提供元がリトライし、自分は重複に対処する必要がある
- 向いている用途
- 必要なときにデータを読み取る・変更する
- 自分が起こしたのではないイベントに反応する
支払いが完了したかを確認するために毎分APIをポーリングすると、リクエストが無駄になるうえ、それでも知るのが遅れます。Webhookは方向を逆にしますが、責任も自分に移ります。エンドポイントを公開し、各メッセージが本物であることを確認し、すばやく応答し、同じイベントが2回届いても対処できなければなりません。このページでは、それぞれの作業をコピーできるコードとともに解説します。
- 提供元に自分のサーバーのURLを登録し、必要なイベントを選びます。
- 提供元は共有シークレットで各イベントの本文に署名し、そのURLにPOSTします。
- エンドポイントは生の本文から署名を再計算し、一致しなければ拒否し、すぐに2xxを返します。
- 実際の処理はバックグラウンドジョブが行い、処理済みのイベントIDはスキップします。
- 本文の生のバイト列に対して検証しましょう。JSONを解析して再シリアライズすると空白が変わり、署名が一致しなくなります。
- 署名の比較は===ではなく、crypto.timingSafeEqualのような定数時間の関数で行いましょう。
- 処理済みのイベントIDは一意制約付きで保存しましょう。リトライや重複があっても、何も起きない無害な処理になります。
- イベントが順番どおりに届くと仮定しないでください。順序が重要な場合は、APIから最新のオブジェクトを取得しましょう。
- 届かなかったイベントを拾うため、1日1回APIをポーリングするゆっくりした照合ジョブを残しておきましょう。
よくある質問
WebhookはAPIの一種ですか?
大まかに言えば、そうです。JSONの本文を持つHTTPリクエストで、逆方向に送られるだけです。リバースAPIと呼ばれることもあります。重要な違いは、誰が通信を開始し、誰が受信のためにオンラインでいる必要があるかです。
ポーリングとWebhookのどちらを使うべきですか?
必要なイベントについて提供元がWebhookを用意していて、公開HTTPSエンドポイントを運用できるならWebhookを使いましょう。Webhookがない場合、ファイアウォールの内側にいる場合、1分程度の遅れが問題にならない少数の確認であれば、ポーリングを使います。
Webhookが本当に提供元から来たとどうやってわかりますか?
多くの提供元は、自分と相手しか知らないシークレットで計算した本文のHMAC SHA-256をヘッダーで送ってきます。たとえばGitHubはsha256=プレフィックス付きのX-Hub-Signature-256を、Stripeはタイムスタンプ付きのStripe-Signatureを使います。何かを信頼する前に、再計算して比較してください。
エンドポイントが停止していたらどうなりますか?
多くの提供元は、失敗した配信を試行の間隔を広げながら、提供元ごとに決まった期間リトライします。たとえばStripeは本番イベントを最大3日間リトライし続けます。それを過ぎると、イベントはAPIかダッシュボードからしか取得できません。
Webhookのハンドラーが処理の前に応答すべきなのはなぜですか?
提供元が応答を待つ時間は短いからです。コードが先にメールを送ったりほかのサービスを呼び出したりすると、すでに処理済みでも配信がタイムアウトしてリトライされることがあります。ジョブをキューに入れて200を返し、処理はその後で行いましょう。
プル:APIを呼び出す
- APIリクエストは、自分のコードが投げかける質問です。注文42をください、今日の登録者を一覧にして、この顧客を作成して、といったものです。いつ聞くかは自分で選べて、すぐに答えが返り、問題があれば明確なエラーも返ります。
- その代わり、変更を知るのは聞いたときだけです。新しいイベントに気づくにはタイマーでポーリングする必要があり、ほとんどのポーリングは空振りに終わります。
プッシュ:Webhookを受信する
- Webhookは、提供元が自分を呼び出すものです。イベントが起きると、その内容を表すJSONを、登録したURLへ通常は数秒以内にPOSTします。
- そのURLにはインターネット上の誰でもPOSTできるので、署名が確認できるまで本文は信頼できません。またネットワークは失敗するので、同じイベントが複数回、あるいは順不同で届くことがあります。良い受信側は、最初から両方に備えて作られています。
両方を組み合わせる
- よく使われる堅牢なパターンでは、Webhookを玄関のベルとして扱います。Webhookはどのオブジェクトが変わったかを知らせ、自分はAPIを呼び出してそのオブジェクトの現在の状態を読み取り、それに基づいて処理します。これで順序の問題や古いペイロードを避けられ、ベルが鳴らなかったものは毎日のポーリングで拾えます。
署名を確認するWebhook受信側
NodeとExpress:生の本文に対するHMAC SHA-256
express.rawで本文をバイト列のまま保持し、署名が一致するようにします。このヘッダー形式はGitHubのsha256=の慣例に従っています。ほかの提供元ではヘッダー名を変えてください。
リトライと重複の扱い
イベントIDに一意インデックスを付けると、2回目の配信では挿入が失敗するため、イベントが何回届いても処理は1回だけ実行されます。
各イベントIDを1回だけ記録する(PostgreSQL)
ON CONFLICT DO NOTHINGは重複の場合に行を返さないので、コードではそれを処理済みとして扱います。
ポーリングという代替手段
ポーリングは運用が簡単ですが、遅く通信量も多くなります。カーソルを保持し、毎回のポーリングで新しいものだけを要求しましょう。
HMAC SHA-256署名チェッカー
本文とシークレットを貼り付けると、提供元が送るはずの署名を計算します。受け取ったヘッダーを貼り付ければ比較できます。すべてWeb Crypto APIを使ってブラウザー内で動作し、どこにも送信されません。
生のリクエスト本文
Webhookシークレット
この本文に付くべき署名
受け取った署名ヘッダー(任意)
一致:この本文とシークレットからこの署名が得られます。
不一致:本文が変わったか、シークレットが間違っているか、ヘッダーが別の形式です。
計算中
無料で始める · クレジットカード不要
関連: ガイド|Webマーケティングと集客を学ぶ
製品
ご利用いただける方
機能
リソース
会社情報
サイトマップを見る