Service Docs 0.168.1-rc.619.0 버전

에러 처리

SDK 의 에러 모양

Hey API client-fetch 는 { data, error } discriminated union 반환:

const res = await BackOfficeTenant.list({ query })
if (res.error) {
  // res.error: { code: string, message: string, ... }
  // 백엔드의 ApiException JSON body 가 그대로 들어옴
} else {
  res.data  // typed response
}

또는 throw 모드 (throwOnError: true config) — 그러면 try/catch.

에러 코드 매핑

백엔드의 ApiException 이 다음 shape JSON 으로 응답:

{
  "code": "user/UserIdDuplicated",
  "message": "userId 'windy' is already used in this tenant"
}

code'<domain>/<reason>' 컨벤션. UI 메시지 매핑 예시:

const MESSAGE_MAP: Record<string, string> = {
  // auth
  'auth/InvalidCredentials': '로그인 정보가 올바르지 않습니다',
  'auth/InvalidToken': '세션이 만료됐습니다. 다시 로그인해주세요',

  // user
  'user/UserIdDuplicated': '이미 사용 중인 사용자 ID 입니다',
  'user/NotFound': '사용자를 찾을 수 없습니다',
  'user/NotManager': '매니저가 아닌 계정입니다',

  // tenant
  'tenant/NotFound': '존재하지 않는 회사입니다',
  'tenant/KeyDuplicated': '이미 사용 중인 회사 ID 입니다',

  // sign-up
  'signUp/EmailDomainNotAllowed': '회사의 허용 이메일 도메인이 아닙니다',

  // email verification
  'emailVerification/InvalidCode': '인증 코드가 만료됐거나 잘못됐습니다',
  'emailVerification/CooldownActive': '잠시 후 다시 시도해주세요 (60초 대기)',

  // password reset
  'passwordReset/InvalidCode': '재설정 코드가 만료됐거나 잘못됐습니다',

  // refresh token
  'refreshToken/Invalid': '세션이 만료됐습니다. 다시 로그인해주세요',
}

function toUserMessage(error: { code?: string; message?: string }): string {
  return (error.code && MESSAGE_MAP[error.code]) ?? error.message ?? '일시적인 오류입니다'
}

자세한 코드 list — API Reference 의 각 endpoint 의 Responses 섹션.

try/catch 또는 mutation onError 패턴

React Query mutation 패턴

const { message } = App.useApp()

const mutation = useMutation({
  mutationFn: async (input) => {
    const res = await ClientAuth.signUp({ body: input })
    if (res.error) throw res.error  // ApiException JSON
    return res.data!
  },
  onError: (err: any) => message.error(toUserMessage(err)),
})

일반 try/catch

try {
  const res = await ClientAuth.signUp({ body: input })
  if (res.error) {
    message.error(toUserMessage(res.error))
    return
  }
  // success
} catch (e) {
  // network error / timeout / abort
  message.error('네트워크 오류입니다. 잠시 후 다시 시도해주세요')
}

자동 처리되는 에러 — frontend 가 신경 X

상황 SDK 자동 처리
401 access expired refresh 호출 + 원 request retry. 성공 시 frontend 는 모름.
401 refresh 도 실패 hooks.onAuthFailure() 호출 — frontend 는 redirect 만 정의.
5xx / 408 / 429 / network exponential backoff retry (max 3). 모두 실패해야 caller 로.
timeout (30초) AbortController abort. caller 에 AbortError 또는 같은 5xx-like 처리.
Multi-tab refresh 동시 Web Locks + BroadcastChannel — 한 tab 만 실제 호출.

→ frontend 가 직접 다루는 에러는 주로 business validation (4xx, code 별 메시지) 와 network 최종 실패 두 카테고리.

디버깅 — DevTools

  • Network 탭에서 401 / 응답 body 의 code 확인
  • Application > Cookies 에서 service_refresh 쿠키 존재 / Domain / Path / HttpOnly 확인
  • Application > Session Storage 에서 app.access 만료 시각 확인
  • BroadcastChannel 의 message 는 chrome://inspect 또는 SDK 의 debug 로그 (별도 PR 에서 추가 예정)