SDK
Client
Browser와 Server 클라이언트 상세 가이드
클라이언트
01.software SDK는 사용 환경에 따라 두 가지 클라이언트를 제공합니다.
BrowserClient
브라우저 환경(Client Component)에서 사용하는 클라이언트입니다.
생성
import { createBrowserClient } from '@01.software/sdk'
const client = createBrowserClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY!
})주요 속성
from(collection)
Supabase 스타일의 쿼리 빌더를 반환합니다.
const queryBuilder = client.from('products')
// 체이닝 방식으로 쿼리 작성
const { data } = await client
.from('products')
.find({ where: { status: { equals: 'published' } } })query
React Query 훅을 제공합니다.
const { data, isLoading } = client.query.useCollection('products', {
limit: 10
})collections
컬렉션별 API 클라이언트를 제공합니다.
const products = await client.collections.products.find({
limit: 10
})설정 옵션
const client = createBrowserClient({
// 필수: API 클라이언트 키
clientKey: string
// 선택: API 베이스 URL
baseUrl?: string // 기본값: 'https://api.01.software'
// 선택: 디버그 모드
debug?: boolean | {
logRequests?: boolean
logResponses?: boolean
logErrors?: boolean
}
// 선택: 재시도 설정
retry?: {
maxRetries?: number // 기본값: 3
retryableStatuses?: number[] // 기본값: [408, 429, 500, 502, 503, 504]
retryDelay?: (attempt: number) => number
}
// 선택: 에러 로거
errorLogger?: {
log: (error: Error) => void
}
})사용 예제
기본 사용
'use client'
import { client } from '@/lib/client'
import { useEffect, useState } from 'react'
export default function ProductsPage() {
const [products, setProducts] = useState([])
useEffect(() => {
async function fetchProducts() {
const { data } = await client.from('products').find({
limit: 10,
where: { status: { equals: 'published' } }
})
setProducts(data?.docs || [])
}
fetchProducts()
}, [])
return (
<div>
{products.map(product => (
<div key={product.id}>{product.name}</div>
))}
</div>
)
}React Query 사용 (권장)
'use client'
import { client } from '@/lib/client'
export default function ProductsPage() {
const { data, isLoading, error } = client.query.useCollection('products', {
limit: 10,
where: { status: { equals: 'published' } }
})
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return (
<div>
{data?.docs.map(product => (
<div key={product.id}>{product.name}</div>
))}
</div>
)
}ServerClient
서버 환경(Server Component, API Route)에서 사용하는 클라이언트입니다.
생성
import { createServerClient } from '@01.software/sdk'
const serverClient = createServerClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY!,
secretKey: process.env.SOFTWARE_SECRET_KEY!,
})secretKey는 절대 브라우저에 노출되어서는 안 됩니다!
주요 속성
BrowserClient의 모든 속성에 더해, 다음을 제공합니다:
api
서버 전용 API 메서드를 제공합니다.
// 주문 생성
const order = await serverClient.api.createOrder({
paymentId: 'pay_123',
orderNumber: generateOrderNumber(),
email: 'user@example.com',
orderProducts: [{
product: 'product_id',
variant: 'variant_id',
quantity: 1,
price: 10000,
}],
totalAmount: 10000,
})
// 주문 업데이트
await serverClient.api.updateOrder('order_id', {
status: 'completed'
})
// 트랜잭션 업데이트
await serverClient.api.updateTransaction('transaction_id', {
status: 'paid'
})사용 예제
Server Component
import { serverClient } from '@/lib/server-client'
export default async function ProductsPage() {
const { data } = await serverClient.from('products').find({
limit: 10,
where: { status: { equals: 'published' } }
})
return (
<div>
{data?.docs.map(product => (
<div key={product.id}>{product.name}</div>
))}
</div>
)
}API Route
import { serverClient } from '@/lib/server-client'
import { generateOrderNumber } from '@01.software/sdk'
import { NextRequest, NextResponse } from 'next/server'
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const order = await serverClient.api.createOrder({
paymentId: body.paymentId,
orderNumber: generateOrderNumber(),
email: body.email,
orderProducts: body.products,
totalAmount: body.totalAmount,
})
return NextResponse.json({ order })
} catch (error) {
return NextResponse.json(
{ error: error.message },
{ status: 500 }
)
}
}Server Action
'use server'
import { serverClient } from '@/lib/server-client'
import { generateOrderNumber } from '@01.software/sdk'
export async function createOrder(formData: FormData) {
const email = formData.get('email') as string
const products = JSON.parse(formData.get('products') as string)
const order = await serverClient.api.createOrder({
paymentId: `pay_${Date.now()}`,
orderNumber: generateOrderNumber(),
email,
orderProducts: products,
totalAmount: products.reduce((sum, p) => sum + p.price * p.quantity, 0),
})
return order
}디버그 모드
개발 중 요청/응답을 로깅하여 디버깅을 쉽게 할 수 있습니다.
전체 디버그 모드
const client = createBrowserClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY!,
debug: true, // 모든 요청/응답/에러 로깅
})선택적 디버그 모드
const client = createBrowserClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY!,
debug: {
logRequests: true, // 요청만 로깅
logResponses: false, // 응답 로깅 안 함
logErrors: true, // 에러만 로깅
},
})로그 출력 예시
[SDK Request] GET /api/collections/products
Query: {"limit":10,"where":{"status":{"equals":"published"}}}
[SDK Response] 200 OK (234ms)
Data: { docs: [...], pagination: {...} }
[SDK Error] Network Error
Message: Failed to fetch
Suggestion: 인터넷 연결을 확인하거나 잠시 후 다시 시도해주세요.프로덕션 환경에서는 디버그 모드를 비활성화하세요.
재시도 로직
네트워크 오류나 서버 에러 시 자동으로 재시도합니다.
const client = createBrowserClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY!,
retry: {
// 최대 재시도 횟수 (기본값: 3)
maxRetries: 3,
// 재시도할 HTTP 상태 코드
retryableStatuses: [408, 429, 500, 502, 503, 504],
// 재시도 지연 시간 (Exponential backoff)
retryDelay: (attempt) => {
// 1초 → 2초 → 4초 → 8초 (최대 10초)
return Math.min(1000 * 2 ** attempt, 10000)
},
},
})기본 동작
- 네트워크 에러는 항상 재시도
- 408, 429, 500, 502, 503, 504 상태 코드는 재시도
- 401, 404 등 클라이언트 에러는 재시도하지 않음
- Exponential backoff 전략 사용
재시도 비활성화
const client = createBrowserClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY!,
retry: {
maxRetries: 0, // 재시도 비활성화
},
})커스텀 에러 처리
에러 발생 시 커스텀 로깅을 수행할 수 있습니다.
const client = createBrowserClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY!,
errorLogger: {
log: (error) => {
// Sentry, LogRocket 등 에러 추적 서비스로 전송
console.error('SDK Error:', error)
// Sentry.captureException(error)
},
},
})베이스 URL 변경
기본 API URL 대신 커스텀 URL을 사용할 수 있습니다.
const client = createBrowserClient({
clientKey: process.env.NEXT_PUBLIC_SOFTWARE_CLIENT_KEY!,
baseUrl: 'https://custom-api.example.com',
})대부분의 경우 기본 베이스 URL(https://api.01.software)을 사용하면 됩니다.
타입 안전성
모든 클라이언트 메서드는 완전한 타입 추론을 제공합니다.
// 타입이 자동으로 추론됨
const { data } = await client.from('products').find()
// data의 타입: { docs: Product[], pagination: PaginationInfo } | undefined
const { data: product } = await client.from('products').findById('id')
// product의 타입: Product | undefined
// 생성 시에도 타입 체크
await client.from('products').create({
name: '상품명', // ✅ OK
price: 10000, // ✅ OK
invalid: 'field', // ❌ 타입 에러
})다음 단계
- 쿼리 빌더 - 데이터 조회 및 조작 방법
- React Query - React 훅으로 데이터 페칭하기
- 에러 핸들링 - 에러 처리 방법