mcpField
E
encore-go-webhook

encore-go-webhook

github.com/encoredev開発30317 回インストール2 日前に更新
リポジトリ

encore-go-webhook について

Encore Go 開発者向けの Webhook エンドポイントスキルです。生の HTTP リクエストの受信と署名検証を扱い、迅速に応答して時間のかかる処理を Pub/Sub に任せる方法を示します。

主な機能

  1. 01生の HTTP エンドポイント定義
  2. 02プロバイダー署名の検証
  3. 03迅速な 2xx 応答
  4. 04時間のかかる処理を Pub/Sub に委譲

活用シーン

  1. 01Stripe や GitHub の Webhook 受信
  2. 02Slack や Shopify のリクエスト検証
  3. 03検証済みイベントの非同期処理への登録

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/encoredev/skills --skill encore-go-webhook

インストール後、Claude Code で/encore-go-webhookを入力して読み込まれたか確認します。

詳細

Encore Go Webhook エンドポイント

手順

//encore:api raw を使用して、サードパーティサービスからの受信 Webhook を受け取ります。raw エンドポイントでは、http.ResponseWriter と *http.Request に直接アクセスできます。これは署名検証に必要であり、検証には通常、解析されていない生のボディが必要です。

1. //encore:api raw でエンドポイントを定義する
package webhooks

import (
    "io"
    "net/http"
)

//encore:api public raw path=/webhooks/stripe method=POST
func StripeWebhook(w http.ResponseWriter, req *http.Request) {
    sig := req.Header.Get("Stripe-Signature")

    // Read the raw body — needed for signature verification.
    body, err := io.ReadAll(req.Body)
    if err != nil {
        http.Error(w, "could not read body", http.StatusBadRequest)
        return
    }

    // Verify signature, parse event, handle, then respond...

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte(`{"received":true}`))
}
2. 署名を検証する

ほとんどのプロバイダーは Webhook に署名します。secrets でシークレットを読み取り(encore-go-secret スキルを参照)、ペイロードを信頼する前に検証してください。

package webhooks

import (
    "github.com/stripe/stripe-go/v76/webhook"
)

var secrets struct {
    StripeWebhookSecret string
}

//encore:api public raw path=/webhooks/stripe method=POST
func StripeWebhook(w http.ResponseWriter, req *http.Request) {
    body, _ := io.ReadAll(req.Body)
    sig := req.Header.Get("Stripe-Signature")

    event, err := webhook.ConstructEvent(body, sig, secrets.StripeWebhookSecret)
    if err != nil {
        http.Error(w, "signature verification failed", http.StatusBadRequest)
        return
    }

    // event is now trusted — handle it.
    _ = event
    w.WriteHeader(http.StatusOK)
}

GitHub の場合は、Webhook シークレットを使用して、X-Hub-Signature-256 ヘッダーの HMAC-SHA256 を生のボディと照合して検証します。

一般的なプロバイダー

プロバイダー署名ヘッダー検証
StripeStripe-Signaturestripe.webhook.ConstructEvent(rawBody, sig, secret)
GitHubX-Hub-Signature-256生のボディに対する HMAC-SHA256
SlackX-Slack-Signaturev0:{timestamp}:{rawBody} に対する HMAC-SHA256
ShopifyX-Shopify-Hmac-Sha256生のボディに対する HMAC-SHA256(base64)
TwilioX-Twilio-SignatureURL + ソート済みフォームフィールドに対する HMAC-SHA1

常に迅速に応答する

Webhook の送信元は、非 2xx または遅い応答に対してリトライします。ペイロードが検証されたらすぐに 2xx で確認応答し、実際の処理はリクエストハンドラー内で行うのではなく、Pub/Sub 経由でキューに投入してください(encore-go-pubsub を参照)。

package webhooks

import (
    "encore.dev/pubsub"
    "net/http"
)

type StripeEvent struct {
    ID   string `json:"id"`
    Type string `json:"type"`
    Data any    `json:"data"`
}

var StripeEvents = pubsub.NewTopic[*StripeEvent]("stripe-events", pubsub.TopicConfig{
    DeliveryGuarantee: pubsub.AtLeastOnce,
})

//encore:api public raw path=/webhooks/stripe method=POST
func StripeWebhook(w http.ResponseWriter, req *http.Request) {
    // ... verify signature, parse event ...

    _, _ = StripeEvents.Publish(req.Context(), &StripeEvent{
        ID: event.ID, Type: string(event.Type), Data: event.Data,
    })
    w.WriteHeader(http.StatusOK)
}

ガイドライン

  • //encore:api raw は Webhook やその他の低レベルな HTTP 連携にのみ使用してください。
  • ペイロードを信頼する前に、常にプロバイダーの署名を検証してください。
  • 常に迅速に 2xx を返してください — 遅い処理は Pub/Sub に任せてください。
  • 署名シークレットは secrets struct{...} に保存してください。インラインで記述しないでください。
  • 自分のサービス内で型付き JSON エンドポイントを使用する場合は、encore-go-api スキルの通常の //encore:api を使用してください。

コメント