API
Rate Limiting
01 SOFTWARE API rate limit 정책 및 최적화 가이드
Rate Limiting
01 SOFTWARE API는 공정한 사용과 시스템 안정성을 위해 rate limit을 적용합니다.
Rate Limit 정책
플랜별 제한
| 플랜 | 월 API 호출 | 분당 요청 | 시간당 요청 |
|---|---|---|---|
| Free | 10,000 | 10 | 200 |
| Starter | 100,000 | 50 | 1,000 |
| Pro | 1,000,000 | 200 | 5,000 |
Rate limit은 테넌트별로 적용됩니다.
Rate Limit Headers
API 응답 헤더에 rate limit 정보가 포함됩니다.
응답 헤더
HTTP/1.1 200 OK
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 195
X-RateLimit-Reset: 1736251200| 헤더 | 설명 |
|---|---|
X-RateLimit-Limit | 시간당 최대 요청 수 |
X-RateLimit-Remaining | 남은 요청 수 |
X-RateLimit-Reset | 리셋 시간 (Unix timestamp) |
Rate Limit 초과
429 응답
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1736251200
Retry-After: 3600에러 응답
{
"errors": [
{
"message": "Rate limit exceeded",
"name": "TooManyRequests",
"extensions": {
"code": "RATE_LIMIT_EXCEEDED",
"retryAfter": 3600
}
}
]
}Rate Limit 확인
SDK를 통한 확인
import { createBrowserClient } from '@01.software/sdk'
const client = createBrowserClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY
})
const response = await client.from('products').find()
// Rate limit 정보 확인
console.log('Remaining:', response.rateLimit.remaining)
console.log('Reset at:', new Date(response.rateLimit.reset * 1000))최적화 전략
1. 캐싱 활용
// React Query로 자동 캐싱
const { data } = client.query.useCollection('products', {
limit: 10
}, {
staleTime: 5 * 60 * 1000, // 5분
cacheTime: 10 * 60 * 1000 // 10분
})2. 배치 요청
// ❌ 여러 번 요청
for (const id of productIds) {
await client.from('products').findById(id) // N회 요청
}
// ✅ 한 번에 요청
const { data } = await client.from('products').find({
where: {
id: { in: productIds }
}
})3. Pagination 최적화
// ✅ 적절한 limit 사용
const { data } = await client.from('products').find({
limit: 20, // 필요한 만큼만
page: 1
})
// ❌ 과도한 limit
const { data } = await client.from('products').find({
limit: 1000 // 불필요하게 많은 데이터
})4. 조건부 요청
// If-None-Match 헤더 사용
const response = await fetch('https://api.01.software/api/products', {
headers: {
'If-None-Match': etag,
'Authorization': `Bearer ${token}`
}
})
if (response.status === 304) {
// 캐시된 데이터 사용
}Retry 전략
Exponential Backoff
SDK는 자동으로 exponential backoff를 적용합니다.
const client = createBrowserClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY,
retry: {
maxRetries: 3,
retryDelay: (attempt) => {
// 1초 → 2초 → 4초
return Math.min(1000 * 2 ** attempt, 10000)
}
}
})수동 Retry
async function fetchWithRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn()
} catch (error) {
if (error.status === 429 && i < maxRetries - 1) {
const retryAfter = error.headers['retry-after'] || (2 ** i)
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000))
continue
}
throw error
}
}
}모니터링
Rate Limit 사용량 조회
// 현재 테넌트의 API 사용량 조회
const { data: usage } = await client.from('api-usage').find({
where: {
tenant: { equals: tenantId },
month: { equals: '2026-01' }
}
})
console.log('Used:', usage.totalCalls)
console.log('Limit:', usage.monthlyLimit)
console.log('Remaining:', usage.monthlyLimit - usage.totalCalls)알림 설정
// 80% 사용 시 알림
if (usage.totalCalls > usage.monthlyLimit * 0.8) {
sendAlert('Rate limit 80% 도달')
}플랜 업그레이드
Rate limit을 초과하는 경우 플랜 업그레이드를 고려하세요.
// 테넌트 플랜 업그레이드
await client.from('tenants').update(tenantId, {
plan: 'pro'
})예외 처리
SDK 에러 핸들링
import { isRateLimitError } from '@01.software/sdk'
try {
const { data } = await client.from('products').find()
} catch (error) {
if (isRateLimitError(error)) {
const retryAfter = error.retryAfter
console.log(`Rate limit exceeded. Retry after ${retryAfter} seconds`)
// 사용자에게 안내
showNotification(`잠시 후 다시 시도해주세요 (${retryAfter}초 후)`)
}
}모범 사례
1. 캐싱 우선
가능한 한 캐싱을 활용하여 API 호출을 줄이세요.
// React Query 자동 캐싱
const { data } = client.query.useCollection('products',
{ limit: 10 },
{ staleTime: 5 * 60 * 1000 } // 5분간 캐시 사용
)2. 필요한 필드만 요청
// GraphQL로 필요한 필드만 요청
const { data } = await client.graphql(`
query {
Products {
docs {
id
name
price
}
}
}
`)3. Webhook 활용
실시간 업데이트가 필요한 경우 polling 대신 webhook을 사용하세요.
// ❌ Polling (비효율적)
setInterval(async () => {
await client.from('orders').find()
}, 5000) // 5초마다 요청
// ✅ Webhook (효율적)
// app/api/webhook/route.ts
export async function POST(request: Request) {
return handleWebhook(request, async (event) => {
if (event.collection === 'orders') {
// 주문 업데이트 처리
}
})
}4. 사용량 모니터링
정기적으로 API 사용량을 확인하고 최적화하세요.
// 주간 리포트
const weeklyUsage = await client.from('api-usage').find({
where: {
createdAt: {
greater_than: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
}
}
})다음 단계
- REST API - REST API 사용법
- GraphQL - GraphQL API 사용법
- SDK Client - SDK로 최적화된 요청
- React Query - 자동 캐싱 및 최적화