|
1 | 1 | /** |
2 | | - * apiFetch — 인증 토큰 자동 첨부 + 만료 시 자동 갱신 |
| 2 | + * Fieldstack 브라우저 인증 유틸리티 |
3 | 3 | * |
4 | | - * Fieldstack 플랫폼의 모든 모듈이 공유하는 인증 fetch 래퍼. |
5 | | - * Vite 번들 내에서 모듈 싱글턴을 공유하므로 main.tsx에서 등록한 |
6 | | - * setSessionExpiredHandler가 모든 모듈의 apiFetch 호출에 적용된다. |
| 4 | + * apiFetch — 인증 토큰 자동 첨부 + 만료 시 자동 갱신 (raw Response 반환) |
| 5 | + * apiCall — apiFetch + Fieldstack JSON 응답({ success, data, error }) 파싱 |
| 6 | + * FS_TOKEN, FS_REFRESH — sessionStorage 키 상수 |
7 | 7 | * |
8 | 8 | * 사용법: |
9 | | - * import { apiFetch, setSessionExpiredHandler } from '@fieldstack/core/browser'; |
| 9 | + * import { apiFetch, apiCall, setSessionExpiredHandler } from '@fieldstack/core/browser'; |
10 | 10 | */ |
11 | 11 |
|
12 | | -const SS_TOKEN = 'fs_token'; |
13 | | -const SS_REFRESH = 'fs_refresh'; |
| 12 | +/** sessionStorage 인증 토큰 키 */ |
| 13 | +export const FS_TOKEN = 'fs_token'; |
| 14 | +/** sessionStorage 리프레시 토큰 키 */ |
| 15 | +export const FS_REFRESH = 'fs_refresh'; |
| 16 | + |
| 17 | +const SS_TOKEN = FS_TOKEN; |
| 18 | +const SS_REFRESH = FS_REFRESH; |
14 | 19 |
|
15 | 20 | type SessionExpiredHandler = () => void; |
16 | 21 | let sessionExpiredHandler: SessionExpiredHandler | null = null; |
@@ -87,3 +92,29 @@ export async function apiFetch(input: string, init: RequestInit = {}): Promise<R |
87 | 92 |
|
88 | 93 | return fetch(input, attachAuth(init, newToken)); |
89 | 94 | } |
| 95 | + |
| 96 | +/** |
| 97 | + * Fieldstack JSON API 호출 유틸리티. |
| 98 | + * |
| 99 | + * apiFetch 위에서 동작하며 Fieldstack 표준 응답 형식을 자동으로 파싱한다: |
| 100 | + * { success: boolean; data?: T; error?: string } |
| 101 | + * |
| 102 | + * - Content-Type: application/json 헤더 자동 첨부 |
| 103 | + * - 빈 응답(204 No Content 등)은 undefined로 반환 |
| 104 | + * - success: false 시 error 메시지로 Error를 throw |
| 105 | + * |
| 106 | + * 모듈 api.ts에서 사용하는 표준 패턴: |
| 107 | + * import { apiCall } from '@fieldstack/core/browser'; |
| 108 | + * const data = await apiCall<MyType>('/api/my-module/items'); |
| 109 | + */ |
| 110 | +export async function apiCall<T>(path: string, init?: RequestInit): Promise<T> { |
| 111 | + const res = await apiFetch(path, { |
| 112 | + ...init, |
| 113 | + headers: { 'Content-Type': 'application/json', ...(init?.headers ?? {}) }, |
| 114 | + }); |
| 115 | + const text = await res.text(); |
| 116 | + if (!text) return undefined as T; |
| 117 | + const json = JSON.parse(text) as { success: boolean; data?: T; error?: unknown }; |
| 118 | + if (!json.success) throw new Error(String(json.error ?? 'API error')); |
| 119 | + return json.data as T; |
| 120 | +} |
0 commit comments