Webhook with Claude Code
Learn about webhook using Claude Code. Practical tips and code examples included.
Webhook とは
Webhookはイベント発生時にHTTPリクエストで外部システムに通知する仕組みです。決済完了通知、Git pushイベント、フォーム送信など多くの場面で使われます。Claude Codeを使えば、堅牢なWebhook実装を効率的に構築できます。
Webhook受信側の実装
import express from "express";
import crypto from "crypto";
const app = express();
// rawBodyを保持するミドルウェア
app.use("/webhooks", express.raw({ type: "application/json" }));
// 署名検証
function verifyWebhookSignature(
payload: Buffer,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expected}`)
);
}
app.post("/webhooks/stripe", async (req, res) => {
const signature = req.headers["stripe-signature"] as string;
const secret = process.env.STRIPE_WEBHOOK_SECRET!;
// 署名検証
if (!verifyWebhookSignature(req.body, signature, secret)) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(req.body.toString());
// 冪等性チェック
const processed = await redis.get(`webhook:${event.id}`);
if (processed) {
return res.json({ status: "already_processed" });
}
try {
await processWebhookEvent(event);
// 処理済みとしてマーク(24時間保持)
await redis.set(`webhook:${event.id}`, "1", "EX", 86400);
res.json({ status: "processed" });
} catch (error) {
console.error("Webhook processing failed:", error);
res.status(500).json({ error: "Processing failed" });
}
});
async function processWebhookEvent(event: any) {
switch (event.type) {
case "payment_intent.succeeded":
await handlePaymentSuccess(event.data.object);
break;
case "customer.subscription.updated":
await handleSubscriptionUpdate(event.data.object);
break;
case "invoice.payment_failed":
await handlePaymentFailed(event.data.object);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
}
Webhook送信側の実装
interface WebhookConfig {
id: string;
url: string;
secret: string;
events: string[];
active: boolean;
}
class WebhookSender {
private maxRetries = 3;
private retryDelays = [1000, 5000, 30000]; // ms
async send(
config: WebhookConfig,
event: string,
payload: Record<string, unknown>
): Promise<void> {
const body = JSON.stringify({
id: crypto.randomUUID(),
event,
timestamp: new Date().toISOString(),
data: payload,
});
const signature = this.sign(body, config.secret);
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
const response = await fetch(config.url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Webhook-Signature": `sha256=${signature}`,
"X-Webhook-Event": event,
"X-Webhook-Delivery": crypto.randomUUID(),
},
body,
signal: AbortSignal.timeout(10000),
});
if (response.ok) {
await this.logDelivery(config.id, event, "success", attempt);
return;
}
if (response.status >= 400 && response.status < 500) {
// クライアントエラーはリトライしない
await this.logDelivery(config.id, event, "client_error", attempt);
return;
}
throw new Error(`HTTP ${response.status}`);
} catch (error) {
if (attempt < this.maxRetries) {
await new Promise((r) => setTimeout(r, this.retryDelays[attempt]));
} else {
await this.logDelivery(config.id, event, "failed", attempt);
throw error;
}
}
}
}
private sign(payload: string, secret: string): string {
return crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
}
private async logDelivery(
configId: string,
event: string,
status: string,
attempts: number
) {
await prisma.webhookDelivery.create({
data: { configId, event, status, attempts },
});
}
}
Webhook登録API
const router = express.Router();
router.post("/api/webhooks", async (req, res) => {
const { url, events } = req.body;
// URLの検証
try {
const parsed = new URL(url);
if (parsed.protocol !== "https:") {
return res.status(400).json({ error: "HTTPS required" });
}
} catch {
return res.status(400).json({ error: "Invalid URL" });
}
// シークレットの生成
const secret = crypto.randomBytes(32).toString("hex");
const webhook = await prisma.webhookConfig.create({
data: {
url,
events,
secret,
active: true,
userId: req.user!.id,
},
});
// シークレットは作成時のみ返す
res.status(201).json({
id: webhook.id,
url: webhook.url,
events: webhook.events,
secret,
});
});
イベントのディスパッチ
class EventDispatcher {
private sender = new WebhookSender();
async dispatch(event: string, payload: Record<string, unknown>) {
// 該当イベントを購読しているWebhookを取得
const configs = await prisma.webhookConfig.findMany({
where: {
active: true,
events: { has: event },
},
});
// 並列で送信(キューに入れる場合はBullMQを使用)
const results = await Promise.allSettled(
configs.map((config) => this.sender.send(config, event, payload))
);
const failed = results.filter((r) => r.status === "rejected");
if (failed.length > 0) {
console.error(`${failed.length}/${configs.length} webhooks failed`);
}
}
}
// Usage example
const dispatcher = new EventDispatcher();
// 注文完了時
async function completeOrder(orderId: string) {
const order = await prisma.order.update({
where: { id: orderId },
data: { status: "completed" },
});
await dispatcher.dispatch("order.completed", {
orderId: order.id,
total: order.total,
customerId: order.customerId,
});
}
Einsatz mit Claude Code
Webhook実装をClaude Codeに依頼する例です。非同期処理についてはジョブキュー・非同期処理、イベント設計はイベント駆動アーキテクチャも参照してください。
Webhookシステムを実装して。
- 受信: Stripe/GitHub Webhookの署名検証
- 送信: HMAC署名付き、リトライ機能付き
- 冪等性の保証
- 配信ログとモニタリング
- 登録・管理用のREST API
WebhookのセキュリティについてはOWASP Webhook Securityを参照してください。Claude Codeの活用法は公式ドキュメントで確認できます。
Zusammenfassung
Webhookはシステム間連携の重要なパターンです。Claude Codeを使えば、署名検証、リトライ、冪等性保証を含む堅牢なWebhook基盤を効率的に構築できます。
Related Posts
Claude Code Hooks meistern: Auto-Formatierung, Auto-Tests und mehr
Erfahren Sie, wie Sie Auto-Formatierung und Auto-Tests mit Claude Code Hooks einrichten. Inklusive praktischer Konfigurationsbeispiele und realer Anwendungsfälle.
Claude Code MCP-Server: Einrichtung und praktische Anwendungsfälle
Ein umfassender Leitfaden zu den MCP-Server-Funktionen von Claude Code. Erfahren Sie, wie Sie externe Tools anbinden, Server konfigurieren, und entdecken Sie praxisnahe Integrationsbeispiele.
Der komplette Leitfaden zum Schreiben von CLAUDE.md: Best Practices für die Projektkonfiguration
Ein umfassender Leitfaden zum Schreiben effektiver CLAUDE.md-Dateien. Erfahren Sie, wie Sie Ihren Tech-Stack, Konventionen und Projektstruktur kommunizieren, um die Ausgabequalität von Claude Code zu maximieren.