Skip to content

Commit

Permalink
[FE] - api 통신을 위한 apiClient 구현 (#55)
Browse files Browse the repository at this point in the history
* feat: API 기본 세팅 추가

- api를 endPoint만 작성하면 쉽게 호출 가능한 형태의 함수인 apiClient 추가

- AbortController를 통해 요청 제한 시간 추가

* feat: apiClient를 axios와 비슷한 형태로 사용가능하도록 수정

- body의 경우 객체 상태로 넘길 수 있도록 타입 설정

* feat: react-query QueryClientProvider 설정 추가
  • Loading branch information
dooohun authored Nov 13, 2024
1 parent c425e40 commit ae65356
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
7 changes: 6 additions & 1 deletion packages/FE/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ import { BrowserRouter } from 'react-router-dom';

import './index.css';
import App from '@/app';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

createRoot(document.getElementById('root')!).render(
<StrictMode>
<BrowserRouter>
<App />
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</BrowserRouter>
</StrictMode>,
);
57 changes: 57 additions & 0 deletions packages/FE/src/shared/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// TODO: env 파일로 관리하기
const BASE_URL = 'http://localhost:3000/';

interface FetchOptions extends Omit<RequestInit, 'body'> {
headers?: Record<string, string>;
body?: unknown;
}

export const apiClient = {
get: (endPoint: string, options: FetchOptions = {}) =>
sendRequest(endPoint, { ...options, method: 'GET' }),
post: (endPoint: string, options: FetchOptions = {}) =>
sendRequest(endPoint, { ...options, method: 'POST' }),
put: (endPoint: string, options: FetchOptions = {}) =>
sendRequest(endPoint, { ...options, method: 'PUT' }),
delete: (endPoint: string, options: FetchOptions = {}) =>
sendRequest(endPoint, { ...options, method: 'DELETE' }),
};

async function sendRequest(endPoint: string, options: FetchOptions = {}, timeout: number = 10000) {
const { headers, body, ...restOptions } = options;

const abortController = new AbortController();
const timeoutId = setTimeout(() => {
abortController.abort();
}, timeout);

try {
const response = await fetch(`${BASE_URL}${endPoint}`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${localStorage.getItem('token')}`,
...headers,
},
// axios처럼 객체를 body로 받을 수 있도록 설정
...(body !== undefined &&
body !== null && {
body: typeof body === 'object' ? JSON.stringify(body) : (body as BodyInit),
}),
signal: abortController.signal,
...restOptions,
});

if (!response.ok) {
const errorMessage = await response.text();
throw new Error(errorMessage || 'API 요청 실패');
}
return response.json();
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
throw new Error('요청 시간이 초과되었습니다.');
}
throw error;
} finally {
clearTimeout(timeoutId);
}
}
2 changes: 1 addition & 1 deletion packages/FE/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"types": ["vite-plugin-svgr/client"],
"types": ["vite-plugin-svgr/client", "node"],

/* Bundler mode */
"moduleResolution": "Bundler",
Expand Down

0 comments on commit ae65356

Please sign in to comment.