From ae653566c5473f58cfa8d9093e35569f7e6df2d9 Mon Sep 17 00:00:00 2001
From: dooohun <74540646+dooohun@users.noreply.github.com>
Date: Wed, 13 Nov 2024 15:57:48 +0900
Subject: [PATCH] =?UTF-8?q?[FE]=20-=20api=20=ED=86=B5=EC=8B=A0=EC=9D=84=20?=
=?UTF-8?q?=EC=9C=84=ED=95=9C=20apiClient=20=EA=B5=AC=ED=98=84=20(#55)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: API 기본 세팅 추가
- api를 endPoint만 작성하면 쉽게 호출 가능한 형태의 함수인 apiClient 추가
- AbortController를 통해 요청 제한 시간 추가
* feat: apiClient를 axios와 비슷한 형태로 사용가능하도록 수정
- body의 경우 객체 상태로 넘길 수 있도록 타입 설정
* feat: react-query QueryClientProvider 설정 추가
---
packages/FE/src/main.tsx | 7 +++-
packages/FE/src/shared/api/index.ts | 57 +++++++++++++++++++++++++++++
packages/FE/tsconfig.json | 2 +-
3 files changed, 64 insertions(+), 2 deletions(-)
create mode 100644 packages/FE/src/shared/api/index.ts
diff --git a/packages/FE/src/main.tsx b/packages/FE/src/main.tsx
index f2f91d7c..6b8a8349 100644
--- a/packages/FE/src/main.tsx
+++ b/packages/FE/src/main.tsx
@@ -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(
-
+
+
+
,
);
diff --git a/packages/FE/src/shared/api/index.ts b/packages/FE/src/shared/api/index.ts
new file mode 100644
index 00000000..e1189941
--- /dev/null
+++ b/packages/FE/src/shared/api/index.ts
@@ -0,0 +1,57 @@
+// TODO: env 파일로 관리하기
+const BASE_URL = 'http://localhost:3000/';
+
+interface FetchOptions extends Omit {
+ headers?: Record;
+ 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);
+ }
+}
diff --git a/packages/FE/tsconfig.json b/packages/FE/tsconfig.json
index e21e04e1..fa9f0d6e 100644
--- a/packages/FE/tsconfig.json
+++ b/packages/FE/tsconfig.json
@@ -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",