01 SOFTWARE
SDK

Utilities

유틸리티 함수 및 헬퍼

Utilities

SDK가 제공하는 유틸리티 함수들입니다.

주문 유틸리티

generateOrderNumber()

날짜 기반 주문 번호를 생성합니다.

import { generateOrderNumber } from '@01.software/sdk'

const orderNumber = generateOrderNumber()
console.log(orderNumber) // "260107123456"

형식

YYMMDDRRRRRR (12자리)

  • YY: 연도 (2자리)
  • MM: 월 (2자리)
  • DD: 일 (2자리)
  • RRRRRR: 랜덤 숫자 (6자리)

Example

// 주문 생성 시
const order = await serverClient.api.createOrder({
  orderNumber: generateOrderNumber(), // "260107482935"
  email: 'user@example.com',
  // ...
})

주문 번호는 유니크하도록 랜덤 숫자를 포함합니다.

formatOrderName()

주문 상품 목록을 주문명으로 포맷팅합니다.

import { formatOrderName } from '@01.software/sdk'

const orderName = formatOrderName(orderProducts)
console.log(orderName) // "iPhone 15 Pro" 또는 "iPhone 15 Pro 외 2건"

Parameters

orderProducts: Array<{
  product: { name: string }
  variant?: { name: string }
}>

Returns

  • 상품이 1개인 경우: "{상품명}"
  • 상품이 여러 개인 경우: "{첫 번째 상품명} 외 {개수}건"

Examples

// 단일 상품
const products = [
  { product: { name: 'iPhone 15 Pro' }, variant: { name: '256GB 블랙' } }
]
formatOrderName(products) // "iPhone 15 Pro"

// 여러 상품
const products = [
  { product: { name: 'iPhone 15 Pro' } },
  { product: { name: 'AirPods Pro' } },
  { product: { name: 'Magic Keyboard' } }
]
formatOrderName(products) // "iPhone 15 Pro 외 2건"

실전 사용

// 주문 생성 시
const order = await serverClient.api.createOrder({
  orderNumber: generateOrderNumber(),
  orderName: formatOrderName(orderProducts),
  email: 'user@example.com',
  orderProducts,
  totalAmount: calculateTotal(orderProducts)
})

// 주문 목록 표시
function OrderList({ orders }) {
  return (
    <div>
      {orders.map(order => (
        <div key={order.id}>
          <h3>{order.orderName}</h3>
          <p>{order.orderNumber}</p>
        </div>
      ))}
    </div>
  )
}

타입 유틸리티

DeepPartial

객체의 모든 속성을 선택적으로 만듭니다 (중첩 포함).

import type { DeepPartial } from '@01.software/sdk'

type Product = {
  name: string
  price: number
  details: {
    weight: number
    dimensions: {
      width: number
      height: number
    }
  }
}

type PartialProduct = DeepPartial<Product>
// 모든 속성이 선택적이 됨

사용 예

// 부분 업데이트
const updates: DeepPartial<Product> = {
  details: {
    dimensions: {
      width: 100 // height는 생략 가능
    }
  }
}

ExtractArrayType

배열 타입에서 요소 타입을 추출합니다.

import type { ExtractArrayType } from '@01.software/sdk'

type Products = Product[]
type SingleProduct = ExtractArrayType<Products> // Product

응답 타입 가드

isSuccessResponse(response)

응답이 성공인지 확인합니다.

import { isSuccessResponse } from '@01.software/sdk'

const response = await client.from('products').find()

if (isSuccessResponse(response)) {
  // TypeScript가 response.data의 타입을 자동 추론
  console.log(response.data.docs)
  console.log(response.data.pagination)
}

isErrorResponse(response)

응답이 에러인지 확인합니다.

import { isErrorResponse } from '@01.software/sdk'

const response = await client.from('products').find()

if (isErrorResponse(response)) {
  // TypeScript가 response.error의 타입을 자동 추론
  console.error(response.error.code)
  console.error(response.error.message)
  console.error(response.error.suggestion)
}

실전 사용

import { isSuccessResponse, isErrorResponse } from '@01.software/sdk'

async function fetchProducts() {
  const response = await client.from('products').find()

  if (isSuccessResponse(response)) {
    return response.data.docs
  }

  if (isErrorResponse(response)) {
    console.error(response.error.getUserMessage())
    throw response.error
  }

  // 절대 실행되지 않음 (TypeScript exhaustiveness check)
  return []
}

에러 타입 가드

isNetworkError(error)

네트워크 에러인지 확인합니다.

import { isNetworkError } from '@01.software/sdk'

try {
  await client.from('products').find()
} catch (error) {
  if (isNetworkError(error)) {
    console.error('네트워크 에러:', error.getUserMessage())
    console.error('제안:', error.suggestion)
  }
}

isApiError(error)

API 에러인지 확인합니다.

import { isApiError } from '@01.software/sdk'

try {
  await client.from('products').find()
} catch (error) {
  if (isApiError(error)) {
    console.error('API 에러:', error.statusCode)
    console.error('메시지:', error.message)
  }
}

isValidationError(error)

검증 에러인지 확인합니다.

import { isValidationError } from '@01.software/sdk'

try {
  await client.from('products').create({
    // 잘못된 데이터
  })
} catch (error) {
  if (isValidationError(error)) {
    console.error('검증 에러:', error.getUserMessage())
  }
}

isTimeoutError(error)

타임아웃 에러인지 확인합니다.

import { isTimeoutError } from '@01.software/sdk'

try {
  await client.from('products').find()
} catch (error) {
  if (isTimeoutError(error)) {
    console.error('요청 시간 초과')
  }
}

에러 클래스

SDKError

모든 SDK 에러의 기본 클래스입니다.

class SDKError extends Error {
  code: string              // 에러 코드
  statusCode?: number       // HTTP 상태 코드 (해당되는 경우)
  userMessage: string       // 사용자 친화적 메시지
  suggestion: string        // 해결 제안

  getUserMessage(): string  // 사용자 친화적 메시지 반환
}

NetworkError

네트워크 관련 에러입니다.

class NetworkError extends SDKError {
  code: 'NETWORK_ERROR'
  userMessage: '네트워크 연결을 확인해주세요.'
  suggestion: '인터넷 연결을 확인하거나 잠시 후 다시 시도해주세요.'
}

ApiError

API 요청 에러입니다.

class ApiError extends SDKError {
  code: 'API_ERROR'
  statusCode: number        // 400, 404, 500 등
  userMessage: string       // 상태 코드에 따른 메시지
  suggestion: string        // 상태 코드에 따른 제안
}

ValidationError

데이터 검증 에러입니다.

class ValidationError extends SDKError {
  code: 'VALIDATION_ERROR'
  userMessage: '입력한 정보를 다시 확인해주세요.'
  suggestion: '필수 필드를 모두 입력했는지 확인해주세요.'
}

TimeoutError

요청 타임아웃 에러입니다.

class TimeoutError extends SDKError {
  code: 'TIMEOUT_ERROR'
  userMessage: '요청 시간이 초과되었습니다.'
  suggestion: '잠시 후 다시 시도해주세요.'
}

실전 활용 예제

포괄적인 에러 처리

import {
  isNetworkError,
  isApiError,
  isValidationError,
  isTimeoutError,
} from '@01.software/sdk'

async function fetchProductsWithErrorHandling() {
  try {
    const { data } = await client.from('products').find()
    return data?.docs || []
  } catch (error) {
    if (isNetworkError(error)) {
      // 네트워크 에러 처리
      toast.error('네트워크 연결을 확인해주세요')
      return []
    }

    if (isApiError(error)) {
      // API 에러 처리
      if (error.statusCode === 404) {
        toast.error('데이터를 찾을 수 없습니다')
      } else if (error.statusCode >= 500) {
        toast.error('서버 오류가 발생했습니다')
      }
      return []
    }

    if (isValidationError(error)) {
      // 검증 에러 처리
      toast.error(error.getUserMessage())
      return []
    }

    if (isTimeoutError(error)) {
      // 타임아웃 에러 처리
      toast.error('요청 시간이 초과되었습니다')
      return []
    }

    // 기타 에러
    console.error('Unknown error:', error)
    toast.error('오류가 발생했습니다')
    return []
  }
}

타입 안전한 응답 처리

import { isSuccessResponse, isErrorResponse } from '@01.software/sdk'

async function handleProductCreation(data: ProductInput) {
  const response = await client.from('products').create(data)

  if (isSuccessResponse(response)) {
    // 성공 - response.data의 타입이 Product로 추론됨
    toast.success(`상품 "${response.data.name}"이 생성되었습니다`)
    router.push(`/products/${response.data.id}`)
    return response.data
  }

  if (isErrorResponse(response)) {
    // 에러 - response.error의 타입이 SDKError로 추론됨
    toast.error(response.error.getUserMessage())
    console.error('Error details:', {
      code: response.error.code,
      message: response.error.message,
      suggestion: response.error.suggestion,
    })
    return null
  }
}

주문 생성 헬퍼

import { generateOrderNumber, formatOrderName } from '@01.software/sdk'

async function createOrderFromCart(cart: CartItem[]) {
  const orderProducts = cart.map(item => ({
    product: item.productId,
    variant: item.variantId,
    quantity: item.quantity,
    price: item.price,
  }))

  const totalAmount = cart.reduce(
    (sum, item) => sum + item.price * item.quantity,
    0
  )

  const order = await serverClient.api.createOrder({
    paymentId: `pay_${Date.now()}`,
    orderNumber: generateOrderNumber(),
    orderName: formatOrderName(
      cart.map(item => ({
        product: { name: item.productName },
        variant: { name: item.variantName },
      }))
    ),
    email: user.email,
    orderProducts,
    totalAmount,
  })

  return order
}

다음 단계

On this page