Rate Limiting
Rate Limiting 은 API 남용을 방지하고 서비스 안정성을 보장합니다.
응답 형식
플랜 한도를 초과하면 429 Too Many Requests 응답이 반환됩니다.
json
{
"error": "Rate limit exceeded",
"level": "app",
"retry_after": "60",
"message": "Your application has exceeded its rate limit. Please wait before making more requests."
}대부분의 Connect Base 에러 응답은
{"error": "..."}형태입니다. Rate limit 응답만level/retry_after/message추가 필드가 함께 반환되며, 일부 신규 엔드포인트(예: push notification 서비스 단계 에러)는 내부적으로{"success": false, "error": {"code", "message", ...}}봉투를 사용할 수 있습니다. ⚠️ SDKApiError.message는 단순error문자열을 기대하므로 봉투 응답에서는[object Object]가 될 수 있습니다 —statusCode로 분기하거나 raw fetch 로 본문을 직접 읽으세요.
SDK 에서 처리
typescript
import { ApiError } from 'connectbase-client'
try {
await cb.database.getData('tbl_xxx')
} catch (e) {
if (e instanceof ApiError && e.statusCode === 429) {
console.warn('Rate limit hit')
}
}Exponential Backoff 패턴
typescript
import { ApiError } from 'connectbase-client'
async function withRetry<T>(fn: () => Promise<T>, maxAttempts = 5): Promise<T> {
for (let i = 0; i < maxAttempts; i++) {
try {
return await fn()
} catch (e) {
if (e instanceof ApiError && e.statusCode === 429 && i < maxAttempts - 1) {
// 1초, 2초, 4초, 8초, 16초 (최대 30초)
const waitMs = Math.min(Math.pow(2, i) * 1000, 30_000)
await new Promise((r) => setTimeout(r, waitMs))
continue
}
throw e
}
}
throw new Error('재시도 한도 초과')
}
// 사용
const result = await withRetry(() => cb.database.getData('tbl_xxx'))Rate Limit 회피 패턴
1. 캐시 레이어 사용 (React Query / SWR)
typescript
import { useQuery } from '@tanstack/react-query'
function useTableData(tableId: string) {
return useQuery({
queryKey: ['table', tableId],
queryFn: () => cb.database.getData(tableId),
staleTime: 60_000 // 1분 동안 캐시 사용
})
}2. 페이지네이션 활용
큰 데이터셋을 한 번에 가져오는 대신 limit / offset 으로 분할:
typescript
// ❌ 비효율적: 매번 1000개 요청
const all = await cb.database.getData('tbl_xxx', { limit: 1000 })
// ✅ 효율적: 사용자가 보는 만큼만 요청
const page = await cb.database.getData('tbl_xxx', { limit: 20, offset: 0 })3. 배치 / 트랜잭션 활용
여러 row 를 한 번에 처리:
typescript
// ❌ 비효율: 각각 호출 (5번의 요청)
for (const item of items) {
await cb.database.createData('tbl_xxx', { data: item })
}
// ✅ 효율: 한 번에 (1번의 요청)
await cb.database.createMany('tbl_xxx', items.map((data) => ({ data })))4. 요청 큐잉 (p-queue)
typescript
import PQueue from 'p-queue'
const queue = new PQueue({
concurrency: 5, // 동시 5개
interval: 1000, // 1초당
intervalCap: 10 // 최대 10개
})
for (const item of items) {
void queue.add(() => processItem(item))
}자세한 패턴은 흔한 에러 & 해결책 #3 을 참고하세요.