Guide
Webhooks
데이터 변경 이벤트 수신
Webhooks
데이터 변경 시 서버로 이벤트를 전송받을 수 있습니다.
개요
Webhook을 설정하면 다음 이벤트 발생 시 지정된 URL로 POST 요청이 전송됩니다:
create- 새 문서 생성update- 문서 수정
Webhook 설정
01.software Admin Panel에서 테넌트 설정의 Webhook URL을 지정합니다.
https://your-domain.com/api/webhookWebhook Payload
{
"collection": "products",
"operation": "create",
"data": {
"id": "product-id",
"title": "상품명",
"price": 10000,
...
}
}SDK로 Webhook 처리
기본 핸들러
// app/api/webhook/route.ts
import { handleWebhook } from '@01.software/sdk'
export async function POST(request: Request) {
return handleWebhook(request, async (event) => {
console.log('Collection:', event.collection)
console.log('Operation:', event.operation)
console.log('Data:', event.data)
// 이벤트 처리 로직
if (event.collection === 'orders' && event.operation === 'create') {
// 새 주문 처리
await sendOrderNotification(event.data)
}
})
}타입 안전한 핸들러
특정 컬렉션에 대한 타입이 지정된 핸들러를 생성할 수 있습니다.
// app/api/webhook/route.ts
import { handleWebhook, createTypedWebhookHandler } from '@01.software/sdk'
// Orders 전용 핸들러
const handleOrderWebhook = createTypedWebhookHandler(
'orders',
async (event) => {
// event.data 타입이 Order로 추론됩니다
console.log('Order Number:', event.data.orderNumber)
console.log('Status:', event.data.status)
console.log('Total:', event.data.totalAmount)
if (event.operation === 'create') {
await sendOrderConfirmation(event.data.email)
}
}
)
export async function POST(request: Request) {
return handleWebhook(request, handleOrderWebhook)
}여러 컬렉션 처리
// app/api/webhook/route.ts
import { handleWebhook } from '@01.software/sdk'
export async function POST(request: Request) {
return handleWebhook(request, async (event) => {
switch (event.collection) {
case 'orders':
await handleOrderEvent(event)
break
case 'products':
await handleProductEvent(event)
break
case 'posts':
await handlePostEvent(event)
break
default:
console.log('Unhandled collection:', event.collection)
}
})
}
async function handleOrderEvent(event: WebhookEvent<'orders'>) {
if (event.operation === 'create') {
await sendOrderNotification(event.data)
}
}
async function handleProductEvent(event: WebhookEvent<'products'>) {
if (event.operation === 'update') {
await revalidatePath(`/products/${event.data.id}`)
}
}
async function handlePostEvent(event: WebhookEvent<'posts'>) {
if (event.operation === 'create') {
await revalidatePath('/blog')
}
}사용 사례
주문 알림
const handleOrderWebhook = createTypedWebhookHandler(
'orders',
async (event) => {
if (event.operation === 'create') {
// 이메일 발송
await sendEmail({
to: event.data.email,
subject: `주문 확인 - ${event.data.orderNumber}`,
body: `주문이 접수되었습니다.`
})
// Slack 알림
await sendSlackNotification({
channel: '#orders',
message: `새 주문: ${event.data.orderNumber}`
})
}
}
)재고 동기화
const handleProductWebhook = createTypedWebhookHandler(
'products',
async (event) => {
if (event.operation === 'update') {
// 외부 시스템과 재고 동기화
await syncInventory({
sku: event.data.sku,
stock: event.data.stock
})
}
}
)캐시 무효화
import { revalidatePath, revalidateTag } from 'next/cache'
const handlePostWebhook = createTypedWebhookHandler(
'posts',
async (event) => {
// 페이지 캐시 무효화
revalidatePath('/blog')
revalidatePath(`/blog/${event.data.slug}`)
// 태그 기반 캐시 무효화
revalidateTag('posts')
}
)응답 형식
Webhook 핸들러는 자동으로 적절한 응답을 반환합니다:
성공
{
"success": true,
"message": "Webhook processed successfully"
}실패
{
"success": false,
"error": "Invalid webhook event"
}보안
프로덕션 환경에서는 Webhook 요청의 출처를 검증하는 것이 좋습니다.
IP 화이트리스트
export async function POST(request: Request) {
const ip = request.headers.get('x-forwarded-for')
if (!allowedIPs.includes(ip)) {
return new Response('Forbidden', { status: 403 })
}
return handleWebhook(request, handler)
}서명 검증
export async function POST(request: Request) {
const signature = request.headers.get('x-webhook-signature')
const body = await request.text()
if (!verifySignature(body, signature)) {
return new Response('Invalid signature', { status: 401 })
}
return handleWebhook(
new Request(request.url, { ...request, body }),
handler
)
}다음 단계
- 에러 처리 - 에러 핸들링
- API Reference - REST API 문서