Implémentation de webhooks avec Claude Code
Découvrez implémentation de webhooks avec Claude Code. Conseils pratiques et exemples de code inclus.
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,
});
}
Claude Codeでの活用
Webhook実装をClaude Codeに依頼する例です。非同期処理についてはジョブキュー・非同期処理、イベント設計はイベント駆動アーキテクチャも参照してください。
Webhookシステムを実装して。
- 受信: Stripe/GitHub Webhookの署名検証
- 送信: HMAC署名付き、リトライ機能付き
- 冪等性の保証
- 配信ログとモニタリング
- 登録・管理用のREST API
WebhookのセキュリティについてはOWASP Webhook Securityを参照してください。Claude Codeの活用法は公式ドキュメントで確認できます。
Summary
Webhookはシステム間連携の重要なパターンです。Claude Codeを使えば、署名検証、リトライ、冪等性保証を含む堅牢なWebhook基盤を効率的に構築できます。
Related Posts
Maîtriser les Hooks de Claude Code : Formatage automatique, tests automatiques et plus encore
Apprenez à configurer le formatage et les tests automatiques avec les hooks de Claude Code. Inclut des exemples de configuration pratiques et des cas d'utilisation concrets.
Configuration des serveurs MCP dans Claude Code et cas d'utilisation pratiques
Un guide complet sur les capacités des serveurs MCP de Claude Code. Apprenez à connecter des outils externes, configurer des serveurs et découvrez des exemples d'intégration concrets.
Le guide complet pour rédiger un CLAUDE.md : Bonnes pratiques de configuration de projet
Un guide approfondi pour rédiger des fichiers CLAUDE.md efficaces. Apprenez à communiquer votre stack technologique, vos conventions et la structure de votre projet pour maximiser la qualité des réponses de Claude Code.