🎣 Supabase Webhooks:自動化で駆動するデータベース
従来のバックエンド開発では、「データが変更された」時に他のアクションをトリガーするのは、非常に面倒でした。
例えば:「ユーザー登録が成功した時、ウェルカムメールを送信する。」 従来の方法:
- フロントエンドが
/api/registerを呼び出す。 - バックエンドでAPI内に
db.users.insert(...)を記述。 - Insertが成功したら、バックエンドが
sendWelcomeEmail(...)を呼び出す。 - メール送信が失敗した場合、リトライロジックも処理する必要がある。
この方法の問題点:もし別のAPI /api/admin/create-user を追加したり、上司が直接データベース管理画面でユーザーを手動追加した場合、これらのユーザーはウェルカムメールを受け取れません。ロジックが特定のAPI内に固定されているからです。
「誰がこのテーブルを操作しても、新しいデータがあれば、データベース自身がメール送信をトリガーする」方法はないでしょうか? あります!それが Database Webhooks(データベーストリガー) です!
1. Database Webhooksとは?
PostgreSQLの基盤には、Trigger(トリガー)という非常に強力な機能があります。これは特定のテーブルで発生する INSERT、UPDATE、DELETE イベントを監視できます。
Supabaseチームはこの基盤機能をラップし、非常に使いやすい Database Webhooks を作成しました。 その動作ロジックは: [このテーブル]で[追加/更新/削除]が発生した時、自動的に[HTTP POSTリクエスト]を[指定したURL]に送信する。
これにより、データベース内部に閉じていたイベントが、一気にインターネット全体に解放されます!
2. 実践シナリオ:注文ステータス更新通知
orders テーブルがあり、status カラム(pending、paid、shipped など)があるとします。
「注文ステータス�� paid に更新されたら、APIを叩いて上司に出荷通知する(またはLine Notifyと連携する)」とします。
ステップ1:Webhookを受信するAPIの作成(Next.js)
まず、Next.jsプロジェクトでWebhookを受信するAPIを準備します:
// src/app/api/webhooks/order-paid/route.ts
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
try {
// 1. Supabaseから送信されるWebhook Payloadを取得
const body = await request.json();
// Supabase Webhookのデータ形式は以下のようになります:
// {
// "type": "UPDATE",
// "table": "orders",
// "record": { "id": "123", "status": "paid", "amount": 500 }, // 新しいデータ
// "old_record": { "id": "123", "status": "pending", "amount": 500 } // 古いデータ
// }
const newRecord = body.record;
const oldRecord = body.old_record;
// 2. ロジック判定:本当に「他のステータスからpaidに変わった」か確認
if (newRecord.status === 'paid' && oldRecord.status !== 'paid') {
console.log(`🎉 支払い通知を受信!注文ID:${newRecord.id},金額:${newRecord.amount}`);
// TODO: ここでメールサービス(Resend)やLine Notifyを呼び出せます!
// sendLineNotify(`注文 ${newRecord.id} が支払われました。すぐに出荷してください!`);
}
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json({ error: 'Webhook処理に失敗しました' }, { status: 500 });
}
}
ステップ2:Supabase管理画面でWebhookを設定
次に、SupabaseにこのAPIにイベントを送信するよう指示します。
- Supabase管理画面にログイン。
- 左メニューで Database -> Webhooks を選択。
- 右上の Create a new Hook をクリック。
- 条件を設定:
- Name:
Order Paid Webhook - Table:
ordersテーブルを選択 - Events:
Updateをチェック(ステータス更新を監視するため)
- Name:
- HTTPリクエストを設定:
- Method:
POST - URL: APIのURLを入力(ローカル開発中の場合はNgrokでlocalhostを公開する必要があります。例:
https://your-ngrok.app/api/webhooks/order-paid)
- Method:
- HTTP Headersを設定:
- Content-type:
application/json - (強く推奨)Secret Tokenを追加:
Authorization: Bearer my-super-secret-token
- Content-type:
- Save hook をクリック。
3. セキュリティ対策:Webhookの真偽を検証する方法
これは非常に恐ろしいことです:/api/webhooks/order-paid はインターネット上に公開されています!
もしハッカーがこのURLを推測し、Postmanで POST リクエストを送信し、偽の {"status": "paid"} 注文データを送り込んだ場合、システムは支払いがあったと誤認し、出荷を繰り返してしまいます!
防御方法:Secret Tokenの検証
SupabaseでWebhookを設定する際(ステップ6)、カスタムHTTPヘッダーを追加しました:
Authorization: Bearer my-super-secret-token
Next.jsのコードにセキュリティチェックを追加します:
// src/app/api/webhooks/order-paid/route.ts
export async function POST(request: Request) {
// 🛡️ セキュリティの第一防御線:キーを確認
const authHeader = request.headers.get('Authorization');
if (authHeader !== `Bearer ${process.env.SUPABASE_WEBHOOK_SECRET}`) {
console.error("ハッキング攻撃!Webhook検証失敗!");
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// キーが正しい場合、出荷ロジックを続行...
const body = await request.json();
// ...
}
これで、SUPABASE_WEBHOOK_SECRET を知っているSupabaseサーバーのみが、あなたのAPIにアクセスできます!
4. Edge Functions vs Webhooks
「SupabaseにはServerless関数(Edge Functions)もあるが、Webhookと何が違うのか?」と疑問に思うかもしれません。
- Edge Functions:Supabase上でホストされるコード(Deno環境)。非常に軽量な計算ロジックに適しています。
- Database Webhooks:イベントを外部にプッシュします。通常はNext.jsプロジェクト(Node.js環境)にイベントを送信することを推奨します。
実践的なアドバイス: Next.js App Routerを使用するフルスタック開発者の場合、WebhookでNext.js APIにイベントを送信することを強く推奨します。 Next.jsには既にORM(Prisma/Drizzle)、メール送信モジュール、決済モジュールが整備されています。Supabase Edge Functionsでロジックを再実装するよりも、すべてのビジネスロジックをNext.jsで一元管理した方が、開発体験が何倍もスムーズです!
Database Webhooksをマスターすれば、アーキテクチャは「受動的なクエリ」から「イベント駆動型(Event-Driven)」に進化します。これが大規模で拡張性のあるシステムを構築する究極の秘訣です!