From 134b24b3c50e6c0fb45a93edfdcc023771de0390 Mon Sep 17 00:00:00 2001 From: cys4585 Date: Wed, 31 Jul 2024 12:21:41 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B0=8F=20API=20=EC=97=B0=EB=8F=99=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84(=EB=B0=B1=EC=97=94=EB=93=9C=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=ED=95=84=EC=9A=94,=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=9B=84?= =?UTF-8?q?=20token=20=EA=B4=80=EB=A6=AC=20=ED=95=84=EC=9A=94=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=ED=99=95=EB=A6=BD=20=ED=95=84=EC=9A=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/endPoints.ts | 1 + frontend/src/apis/user.ts | 20 +++++++++++ .../src/components/LoginForm/LoginForm.tsx | 35 ++++++++++++++++--- 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 frontend/src/apis/user.ts diff --git a/frontend/src/apis/endPoints.ts b/frontend/src/apis/endPoints.ts index 3566e42dd..6689713d5 100644 --- a/frontend/src/apis/endPoints.ts +++ b/frontend/src/apis/endPoints.ts @@ -5,5 +5,6 @@ const getEndpoint = (string: string) => { const ENDPOINTS = { moim: getEndpoint('v1/moim'), moims: getEndpoint('v1/moim'), + auth: getEndpoint('v1/auth'), }; export default ENDPOINTS; diff --git a/frontend/src/apis/user.ts b/frontend/src/apis/user.ts new file mode 100644 index 000000000..5b45698a3 --- /dev/null +++ b/frontend/src/apis/user.ts @@ -0,0 +1,20 @@ +import { checkStatus, defaultOptions } from './apiconfig'; +import ENDPOINTS from './endPoints'; + +export const login = async (loginInputInfo: { nickname: string }) => { + const url = `${ENDPOINTS.auth}/login`; + + const requestBody = { + method: 'POST', + defaultOptions, + body: JSON.stringify(loginInputInfo), + }; + + const response = await fetch(url, requestBody); + console.log(response); + + checkStatus(response); + + const json = await response.json(); + return json.data; +}; diff --git a/frontend/src/components/LoginForm/LoginForm.tsx b/frontend/src/components/LoginForm/LoginForm.tsx index d4fe08278..bfd3f832e 100644 --- a/frontend/src/components/LoginForm/LoginForm.tsx +++ b/frontend/src/components/LoginForm/LoginForm.tsx @@ -1,15 +1,42 @@ import Button from '@_components/Button/Button'; import LabeledInput from '@_components/Input/MoimInput'; import * as S from './LoginForm.style'; +import { useEffect, useState } from 'react'; +import { login } from '@_apis/user'; +import { useNavigate } from 'react-router-dom'; +import ROUTES from '@_constants/routes'; +// TODO: 로그인 기능 요구사항 변경 예정 export default function LoginForm() { + const navigate = useNavigate(); + + const [nickname, setNickname] = useState(''); + const [isValid, setIsValid] = useState(false); + + const handleNicknameChange = (e: React.ChangeEvent) => { + setNickname(e.target.value); + }; + + const handleLoginFormSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + await login({ nickname }); + navigate(ROUTES.main); + }; + + useEffect(() => { + setIsValid(nickname.length > 0); + }, [nickname]); + return ( -
+
- - +
-
From 2bf54260d0c6fb5cc81d55f1e909ce45e7a0bfdf Mon Sep 17 00:00:00 2001 From: cys4585 Date: Wed, 31 Jul 2024 14:59:57 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feature:=20api=20=EC=9D=B8=ED=84=B0?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EC=83=81=ED=99=94=20(ac?= =?UTF-8?q?cess=20token,=20refresh=20token=20=EB=8C=80=EC=9D=91=EC=97=90?= =?UTF-8?q?=20=EC=9C=A0=EB=A6=AC=ED=95=A0=20=EA=B2=83=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8C=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/apiClient.ts | 116 +++++++++++++++++++++++++++++++++ frontend/src/apis/gets.ts | 8 +++ frontend/src/apis/posts.ts | 7 ++ frontend/src/apis/user.ts | 19 +----- 4 files changed, 133 insertions(+), 17 deletions(-) create mode 100644 frontend/src/apis/apiClient.ts diff --git a/frontend/src/apis/apiClient.ts b/frontend/src/apis/apiClient.ts new file mode 100644 index 000000000..2cf0c0bdd --- /dev/null +++ b/frontend/src/apis/apiClient.ts @@ -0,0 +1,116 @@ +const defaultHeaders = { + 'Content-Type': 'application/json', +}; + +const baseURL = process.env.BASE_URL; + +class ApiClient { + private static addBaseURL(url: string) { + if (url[0] !== '/') url = '/' + url; + return baseURL + '/v1' + url; + } + + private static getHeaders(token?: string) { + const headers = new Headers(defaultHeaders); + if (token) { + headers.append('Authorization', `Bearer ${token}`); + } + return headers; + } + + static async get(path = '', config = {}) { + const url = this.addBaseURL(path); + + const res = await fetch(url, { + method: 'GET', + headers: this.getHeaders(), + ...config, + }); + + if (!res.ok) { + console.log(res); + throw new Error(res.statusText); + } + + return res.json(); + } + + static async post(path = '', data = {}, config = {}) { + const url = this.addBaseURL(path); + + const res = await fetch(url, { + method: 'POST', + headers: this.getHeaders(), + body: JSON.stringify(data), + ...config, + }); + + if (!res.ok) { + console.log(res); + throw new Error(res.statusText); + } + + const contentType = res.headers.get('Content-Type'); + if (contentType && contentType.includes('application/json')) { + return res.json(); + } + + return; + } + + static async put(path = '', data = {}, config = {}) { + const url = this.addBaseURL(path); + + const res = await fetch(url, { + method: 'PUT', + headers: this.getHeaders(), + body: JSON.stringify(data), + ...config, + }); + + if (!res.ok) { + console.log(res); + throw new Error(res.statusText); + } + + return res.json(); + } + + static async patch(path = '', data = {}, config = {}) { + const url = this.addBaseURL(path); + + const res = await fetch(url, { + method: 'patch', + headers: this.getHeaders(), + body: JSON.stringify(data), + ...config, + }); + + if (!res.ok) { + console.log(res); + throw new Error(res.statusText); + } + + return res.json(); + } + + static async delete(path = '', data = {}, config = {}) { + const url = this.addBaseURL(path); + + const res = await fetch(url, { + method: 'DELETE', + headers: this.getHeaders(), + body: JSON.stringify(data), + ...config, + }); + + if (!res.ok) { + console.log(res); + throw new Error(res.statusText); + } + + return res.json(); + } +} + +export default ApiClient; diff --git a/frontend/src/apis/gets.ts b/frontend/src/apis/gets.ts index d3dd80bae..d2df84950 100644 --- a/frontend/src/apis/gets.ts +++ b/frontend/src/apis/gets.ts @@ -16,6 +16,10 @@ export const getMoims = async (): Promise => { const json = (await response.json()) as GetMoims; return json.data.moims; }; +// export const getMoims = async (): Promise => { +// const json: GetMoims = await ApiClient.get('moim'); +// return json.data.moims; +// }; export const getMoim = async (moimId: number): Promise => { const url = `${ENDPOINTS.moim}/${moimId}`; @@ -27,3 +31,7 @@ export const getMoim = async (moimId: number): Promise => { const json = (await response.json()) as GetMoim; return json.data; }; +// export const getMoim = async (moimId: number): Promise => { +// const json: GetMoim = await ApiClient.get(`moim/${moimId}`); +// return json.data; +// }; diff --git a/frontend/src/apis/posts.ts b/frontend/src/apis/posts.ts index b39805ab4..2f461e663 100644 --- a/frontend/src/apis/posts.ts +++ b/frontend/src/apis/posts.ts @@ -23,6 +23,10 @@ export const postMoim = async (moim: MoimInputInfo): Promise => { const json = (await response.json()) as PostMoim; return json.data; }; +// export const postMoim = async (moim: MoimInputInfo): Promise => { +// const json = await ApiClient.post('moim', moim); +// return json.data; +// }; export const postJoinMoim = async (moimId: number, nickname: string) => { const url = `${ENDPOINTS.moims}/join`; @@ -35,3 +39,6 @@ export const postJoinMoim = async (moimId: number, nickname: string) => { await checkStatus(response); }; +// export const postJoinMoim = async (moimId: number, nickname: string) => { +// await ApiClient.post('moim/join', { moimId, nickname }); +// }; diff --git a/frontend/src/apis/user.ts b/frontend/src/apis/user.ts index 5b45698a3..4a473739d 100644 --- a/frontend/src/apis/user.ts +++ b/frontend/src/apis/user.ts @@ -1,20 +1,5 @@ -import { checkStatus, defaultOptions } from './apiconfig'; -import ENDPOINTS from './endPoints'; +import ApiClient from './apiClient'; export const login = async (loginInputInfo: { nickname: string }) => { - const url = `${ENDPOINTS.auth}/login`; - - const requestBody = { - method: 'POST', - defaultOptions, - body: JSON.stringify(loginInputInfo), - }; - - const response = await fetch(url, requestBody); - console.log(response); - - checkStatus(response); - - const json = await response.json(); - return json.data; + return await ApiClient.post('auth/login', loginInputInfo); }; From 39e546f00ff22aae8fad924a58d4bd68d344252a Mon Sep 17 00:00:00 2001 From: cys4585 Date: Wed, 31 Jul 2024 15:02:23 +0900 Subject: [PATCH 03/11] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=A3=BC=EC=84=9D=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/gets.ts | 8 -------- frontend/src/apis/posts.ts | 7 ------- 2 files changed, 15 deletions(-) diff --git a/frontend/src/apis/gets.ts b/frontend/src/apis/gets.ts index d2df84950..d3dd80bae 100644 --- a/frontend/src/apis/gets.ts +++ b/frontend/src/apis/gets.ts @@ -16,10 +16,6 @@ export const getMoims = async (): Promise => { const json = (await response.json()) as GetMoims; return json.data.moims; }; -// export const getMoims = async (): Promise => { -// const json: GetMoims = await ApiClient.get('moim'); -// return json.data.moims; -// }; export const getMoim = async (moimId: number): Promise => { const url = `${ENDPOINTS.moim}/${moimId}`; @@ -31,7 +27,3 @@ export const getMoim = async (moimId: number): Promise => { const json = (await response.json()) as GetMoim; return json.data; }; -// export const getMoim = async (moimId: number): Promise => { -// const json: GetMoim = await ApiClient.get(`moim/${moimId}`); -// return json.data; -// }; diff --git a/frontend/src/apis/posts.ts b/frontend/src/apis/posts.ts index 2f461e663..b39805ab4 100644 --- a/frontend/src/apis/posts.ts +++ b/frontend/src/apis/posts.ts @@ -23,10 +23,6 @@ export const postMoim = async (moim: MoimInputInfo): Promise => { const json = (await response.json()) as PostMoim; return json.data; }; -// export const postMoim = async (moim: MoimInputInfo): Promise => { -// const json = await ApiClient.post('moim', moim); -// return json.data; -// }; export const postJoinMoim = async (moimId: number, nickname: string) => { const url = `${ENDPOINTS.moims}/join`; @@ -39,6 +35,3 @@ export const postJoinMoim = async (moimId: number, nickname: string) => { await checkStatus(response); }; -// export const postJoinMoim = async (moimId: number, nickname: string) => { -// await ApiClient.post('moim/join', { moimId, nickname }); -// }; From a4cd149523ead45799a72802bf99750a36563759 Mon Sep 17 00:00:00 2001 From: cys4585 Date: Wed, 31 Jul 2024 16:10:53 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feature:=20=ED=85=8C=EB=B0=94=EB=95=8C?= =?UTF-8?q?=EB=AC=B8=EC=97=90=20=EC=BB=A4=EB=B0=8B=20=EC=98=AC=EB=A6=BC(?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=9B=84=20API=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=EC=8B=9C=20auth=20=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/apiClient.ts | 59 +++++++++++++++---- frontend/src/apis/gets.ts | 13 +++- .../src/components/LoginForm/LoginForm.tsx | 6 +- frontend/src/utils/tokenManager.ts | 13 ++++ 4 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 frontend/src/utils/tokenManager.ts diff --git a/frontend/src/apis/apiClient.ts b/frontend/src/apis/apiClient.ts index 2cf0c0bdd..d7e582492 100644 --- a/frontend/src/apis/apiClient.ts +++ b/frontend/src/apis/apiClient.ts @@ -1,3 +1,5 @@ +import { getToken } from '@_utils/tokenManager'; + const defaultHeaders = { 'Content-Type': 'application/json', }; @@ -10,7 +12,7 @@ class ApiClient { return baseURL + '/v1' + url; } - private static getHeaders(token?: string) { + private static getHeaders(token: string | null) { const headers = new Headers(defaultHeaders); if (token) { headers.append('Authorization', `Bearer ${token}`); @@ -18,12 +20,13 @@ class ApiClient { return headers; } - static async get(path = '', config = {}) { + static async get(path = '', config = {}, isRequiredAuth = false) { const url = this.addBaseURL(path); + const token = isRequiredAuth ? getToken() : null; const res = await fetch(url, { method: 'GET', - headers: this.getHeaders(), + headers: this.getHeaders(token), ...config, }); @@ -35,12 +38,17 @@ class ApiClient { return res.json(); } - static async post(path = '', data = {}, config = {}) { + static async getWithAuth(path = '', config = {}) { + return this.get(path, config, true); + } + + static async post(path = '', data = {}, config = {}, isRequiredAuth = false) { const url = this.addBaseURL(path); + const token = isRequiredAuth ? getToken() : null; const res = await fetch(url, { method: 'POST', - headers: this.getHeaders(), + headers: this.getHeaders(token), body: JSON.stringify(data), ...config, }); @@ -58,12 +66,17 @@ class ApiClient { return; } - static async put(path = '', data = {}, config = {}) { + static async postWithAuth(path = '', data = {}, config = {}) { + return this.post(path, data, config, true); + } + + static async put(path = '', data = {}, config = {}, isRequiredAuth = false) { const url = this.addBaseURL(path); + const token = isRequiredAuth ? getToken() : null; const res = await fetch(url, { method: 'PUT', - headers: this.getHeaders(), + headers: this.getHeaders(token), body: JSON.stringify(data), ...config, }); @@ -76,12 +89,22 @@ class ApiClient { return res.json(); } - static async patch(path = '', data = {}, config = {}) { + static async putWithAuth(path = '', data = {}, config = {}) { + return this.put(path, data, config, true); + } + + static async patch( + path = '', + data = {}, + config = {}, + isRequiredAuth = false, + ) { const url = this.addBaseURL(path); + const token = isRequiredAuth ? getToken() : null; const res = await fetch(url, { method: 'patch', - headers: this.getHeaders(), + headers: this.getHeaders(token), body: JSON.stringify(data), ...config, }); @@ -94,12 +117,22 @@ class ApiClient { return res.json(); } - static async delete(path = '', data = {}, config = {}) { + static async patchWithAuth(path = '', data = {}, config = {}) { + return this.patch(path, data, config, true); + } + + static async delete( + path = '', + data = {}, + config = {}, + isRequiredAuth = false, + ) { const url = this.addBaseURL(path); + const token = isRequiredAuth ? getToken() : null; const res = await fetch(url, { method: 'DELETE', - headers: this.getHeaders(), + headers: this.getHeaders(token), body: JSON.stringify(data), ...config, }); @@ -111,6 +144,10 @@ class ApiClient { return res.json(); } + + static async deleteWithAuth(path = '', data = {}, config = {}) { + return this.delete(path, data, config, true); + } } export default ApiClient; diff --git a/frontend/src/apis/gets.ts b/frontend/src/apis/gets.ts index d3dd80bae..71e609dc0 100644 --- a/frontend/src/apis/gets.ts +++ b/frontend/src/apis/gets.ts @@ -2,12 +2,13 @@ import ENDPOINTS from '@_apis/endPoints'; import { GetMoim, GetMoims } from '@_apis/responseTypes'; import { MoimInfo } from '@_types/index'; import { checkStatus, defaultOptions } from './apiconfig'; +import ApiClient from './apiClient'; const defaultGetOptions = { method: 'GET', ...defaultOptions, }; -export const getMoims = async (): Promise => { +export const getMoims1 = async (): Promise => { const url = ENDPOINTS.moims; const response = await fetch(url, defaultGetOptions); @@ -16,8 +17,12 @@ export const getMoims = async (): Promise => { const json = (await response.json()) as GetMoims; return json.data.moims; }; +export const getMoims = async (): Promise => { + const json: GetMoims = await ApiClient.getWithAuth('moim'); + return json.data.moims; +}; -export const getMoim = async (moimId: number): Promise => { +export const getMoim2 = async (moimId: number): Promise => { const url = `${ENDPOINTS.moim}/${moimId}`; const response = await fetch(url, defaultGetOptions); @@ -27,3 +32,7 @@ export const getMoim = async (moimId: number): Promise => { const json = (await response.json()) as GetMoim; return json.data; }; +export const getMoim = async (moimId: number): Promise => { + const json: GetMoim = await ApiClient.get(`moim/${moimId}`); + return json.data; +}; diff --git a/frontend/src/components/LoginForm/LoginForm.tsx b/frontend/src/components/LoginForm/LoginForm.tsx index bfd3f832e..11930fc7f 100644 --- a/frontend/src/components/LoginForm/LoginForm.tsx +++ b/frontend/src/components/LoginForm/LoginForm.tsx @@ -5,6 +5,7 @@ import { useEffect, useState } from 'react'; import { login } from '@_apis/user'; import { useNavigate } from 'react-router-dom'; import ROUTES from '@_constants/routes'; +import { setToken } from '@_utils/tokenManager'; // TODO: 로그인 기능 요구사항 변경 예정 export default function LoginForm() { @@ -19,7 +20,10 @@ export default function LoginForm() { const handleLoginFormSubmit = async (e: React.FormEvent) => { e.preventDefault(); - await login({ nickname }); + + const response = await login({ nickname }); + console.log(response); + setToken(response.data.accessToken); navigate(ROUTES.main); }; diff --git a/frontend/src/utils/tokenManager.ts b/frontend/src/utils/tokenManager.ts new file mode 100644 index 000000000..484c4cf3a --- /dev/null +++ b/frontend/src/utils/tokenManager.ts @@ -0,0 +1,13 @@ +const TOKEN_KEY = 'access-token'; + +export const setToken = (token: string): void => { + localStorage.setItem(TOKEN_KEY, token); +}; + +export const getToken = (): string | null => { + return localStorage.getItem(TOKEN_KEY); +}; + +export const removeToken = (): void => { + localStorage.removeItem(TOKEN_KEY); +}; From 62e534eabf1df0a7077d423abf39678f03f89721 Mon Sep 17 00:00:00 2001 From: cys4585 Date: Wed, 31 Jul 2024 16:27:25 +0900 Subject: [PATCH 05/11] =?UTF-8?q?style:=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD(user=20->=20auth),=20baseURL=EC=97=90=20api?= =?UTF-8?q?=20=EB=B2=84=EC=A0=84=EB=8F=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/apiClient.ts | 4 ++-- frontend/src/apis/{user.ts => auth.ts} | 0 frontend/src/components/LoginForm/LoginForm.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename frontend/src/apis/{user.ts => auth.ts} (100%) diff --git a/frontend/src/apis/apiClient.ts b/frontend/src/apis/apiClient.ts index d7e582492..a186e86a5 100644 --- a/frontend/src/apis/apiClient.ts +++ b/frontend/src/apis/apiClient.ts @@ -4,12 +4,12 @@ const defaultHeaders = { 'Content-Type': 'application/json', }; -const baseURL = process.env.BASE_URL; +const baseURL = `${process.env.BASE_URL}/v1`; class ApiClient { private static addBaseURL(url: string) { if (url[0] !== '/') url = '/' + url; - return baseURL + '/v1' + url; + return baseURL + url; } private static getHeaders(token: string | null) { diff --git a/frontend/src/apis/user.ts b/frontend/src/apis/auth.ts similarity index 100% rename from frontend/src/apis/user.ts rename to frontend/src/apis/auth.ts diff --git a/frontend/src/components/LoginForm/LoginForm.tsx b/frontend/src/components/LoginForm/LoginForm.tsx index 11930fc7f..d1d0256a4 100644 --- a/frontend/src/components/LoginForm/LoginForm.tsx +++ b/frontend/src/components/LoginForm/LoginForm.tsx @@ -2,10 +2,10 @@ import Button from '@_components/Button/Button'; import LabeledInput from '@_components/Input/MoimInput'; import * as S from './LoginForm.style'; import { useEffect, useState } from 'react'; -import { login } from '@_apis/user'; import { useNavigate } from 'react-router-dom'; import ROUTES from '@_constants/routes'; import { setToken } from '@_utils/tokenManager'; +import { login } from '@_apis/auth'; // TODO: 로그인 기능 요구사항 변경 예정 export default function LoginForm() { From 05bf177be1d92e6337d54037da5a4722944d881b Mon Sep 17 00:00:00 2001 From: cys4585 Date: Wed, 31 Jul 2024 16:29:01 +0900 Subject: [PATCH 06/11] =?UTF-8?q?style:=20=EA=B8=B0=EC=A1=B4=20API=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=9B=90=EC=83=81=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/gets.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/frontend/src/apis/gets.ts b/frontend/src/apis/gets.ts index 71e609dc0..d3dd80bae 100644 --- a/frontend/src/apis/gets.ts +++ b/frontend/src/apis/gets.ts @@ -2,13 +2,12 @@ import ENDPOINTS from '@_apis/endPoints'; import { GetMoim, GetMoims } from '@_apis/responseTypes'; import { MoimInfo } from '@_types/index'; import { checkStatus, defaultOptions } from './apiconfig'; -import ApiClient from './apiClient'; const defaultGetOptions = { method: 'GET', ...defaultOptions, }; -export const getMoims1 = async (): Promise => { +export const getMoims = async (): Promise => { const url = ENDPOINTS.moims; const response = await fetch(url, defaultGetOptions); @@ -17,12 +16,8 @@ export const getMoims1 = async (): Promise => { const json = (await response.json()) as GetMoims; return json.data.moims; }; -export const getMoims = async (): Promise => { - const json: GetMoims = await ApiClient.getWithAuth('moim'); - return json.data.moims; -}; -export const getMoim2 = async (moimId: number): Promise => { +export const getMoim = async (moimId: number): Promise => { const url = `${ENDPOINTS.moim}/${moimId}`; const response = await fetch(url, defaultGetOptions); @@ -32,7 +27,3 @@ export const getMoim2 = async (moimId: number): Promise => { const json = (await response.json()) as GetMoim; return json.data; }; -export const getMoim = async (moimId: number): Promise => { - const json: GetMoim = await ApiClient.get(`moim/${moimId}`); - return json.data; -}; From 2b6bc6455f73fba0371a2ece54997b57c90b4372 Mon Sep 17 00:00:00 2001 From: cys4585 Date: Wed, 31 Jul 2024 17:21:05 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feature:=20=EB=AF=B8=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EC=83=81=ED=83=9C=EC=8B=9C=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=EB=A1=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=8B=A4=EC=9D=B4=EB=A0=89=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/.storybook/main.ts | 1 + frontend/jest.config.ts | 1 + frontend/src/App.tsx | 2 +- frontend/src/apis/gets.ts | 26 ++++-------------- frontend/src/apis/posts.ts | 32 +++-------------------- frontend/src/routes/ProtectedRoute.tsx | 17 ++++++++++++ frontend/src/{ => routes}/router.tsx | 21 +++++++++++++-- frontend/src/utils/checkAuthentication.ts | 5 ++++ frontend/tsconfig.json | 3 ++- frontend/webpack.common.js | 1 + 10 files changed, 55 insertions(+), 54 deletions(-) create mode 100644 frontend/src/routes/ProtectedRoute.tsx rename frontend/src/{ => routes}/router.tsx (65%) create mode 100644 frontend/src/utils/checkAuthentication.ts diff --git a/frontend/.storybook/main.ts b/frontend/.storybook/main.ts index bf3e37456..0cadd0ef0 100644 --- a/frontend/.storybook/main.ts +++ b/frontend/.storybook/main.ts @@ -44,6 +44,7 @@ const config: StorybookConfig = { '@_pages': path.resolve(__dirname, '../src/pages'), '@_types': path.resolve(__dirname, '../src/types'), '@_utils': path.resolve(__dirname, '../src/utils'), + '@_routes': path.resolve(__dirname, 'src/routes'), }; } diff --git a/frontend/jest.config.ts b/frontend/jest.config.ts index b50cfe739..00908ea80 100644 --- a/frontend/jest.config.ts +++ b/frontend/jest.config.ts @@ -22,6 +22,7 @@ const config: Config = { '^@_pages/(.*)$': '/src/pages/$1', '^@_types/(.*)$': '/src/types/$1', '^@_utils/(.*)$': '/src/utils/$1', + '^@_routes/(.*)$': '/src/routes/$1', }, }; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f1223cd5b..8806636c0 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,9 +4,9 @@ import { RouterProvider } from 'react-router-dom'; import createQueryClient from './queryClient'; import fonts from '@_common/font.style'; import reset from './common/reset.style'; -import router from './router'; import { useMemo } from 'react'; import { theme } from '@_common/theme/theme.style'; +import router from '@_routes/router'; export default function App() { const queryClient = useMemo(createQueryClient, []); diff --git a/frontend/src/apis/gets.ts b/frontend/src/apis/gets.ts index d3dd80bae..52c56b98b 100644 --- a/frontend/src/apis/gets.ts +++ b/frontend/src/apis/gets.ts @@ -1,29 +1,13 @@ -import ENDPOINTS from '@_apis/endPoints'; -import { GetMoim, GetMoims } from '@_apis/responseTypes'; +// ./src/apis/gets.ts import { MoimInfo } from '@_types/index'; -import { checkStatus, defaultOptions } from './apiconfig'; +import ApiClient from './apiClient'; +import { GetMoim, GetMoims } from './responseTypes'; -const defaultGetOptions = { - method: 'GET', - ...defaultOptions, -}; export const getMoims = async (): Promise => { - const url = ENDPOINTS.moims; - - const response = await fetch(url, defaultGetOptions); - - checkStatus(response); - const json = (await response.json()) as GetMoims; + const json: GetMoims = await ApiClient.getWithAuth('moim'); return json.data.moims; }; - export const getMoim = async (moimId: number): Promise => { - const url = `${ENDPOINTS.moim}/${moimId}`; - - const response = await fetch(url, defaultGetOptions); - - checkStatus(response); - - const json = (await response.json()) as GetMoim; + const json: GetMoim = await ApiClient.getWithAuth(`moim/${moimId}`); return json.data; }; diff --git a/frontend/src/apis/posts.ts b/frontend/src/apis/posts.ts index b39805ab4..0ab8d77e3 100644 --- a/frontend/src/apis/posts.ts +++ b/frontend/src/apis/posts.ts @@ -1,37 +1,11 @@ -import { checkStatus, defaultOptions } from './apiconfig'; - -import ENDPOINTS from '@_apis/endPoints'; import { MoimInputInfo } from '@_types/index'; -import { PostMoim } from '@_apis/responseTypes'; +import ApiClient from './apiClient'; -const defaultPostOptions = { - method: 'POST', - ...defaultOptions, -}; export const postMoim = async (moim: MoimInputInfo): Promise => { - const url = ENDPOINTS.moim; - - const options = { - ...defaultPostOptions, - body: JSON.stringify(moim), - }; - - const response = await fetch(url, options); - - checkStatus(response); - - const json = (await response.json()) as PostMoim; + const json = await ApiClient.postWithAuth('moim', moim); return json.data; }; export const postJoinMoim = async (moimId: number, nickname: string) => { - const url = `${ENDPOINTS.moims}/join`; - const options = { - ...defaultPostOptions, - body: JSON.stringify({ moimId, nickname }), - }; - - const response = await fetch(url, options); - - await checkStatus(response); + await ApiClient.postWithAuth('moim/join', { moimId, nickname }); }; diff --git a/frontend/src/routes/ProtectedRoute.tsx b/frontend/src/routes/ProtectedRoute.tsx new file mode 100644 index 000000000..57c8cb264 --- /dev/null +++ b/frontend/src/routes/ProtectedRoute.tsx @@ -0,0 +1,17 @@ +import ROUTES from '@_constants/routes'; +import { checkAuthentication } from '@_utils/checkAuthentication'; +import { PropsWithChildren } from 'react'; +import { Navigate, useLocation } from 'react-router-dom'; + +export default function ProtectedRoute(props: PropsWithChildren) { + const { children } = props; + + const isAuthenticated = checkAuthentication(); + const location = useLocation(); + + return isAuthenticated ? ( + children + ) : ( + + ); +} diff --git a/frontend/src/router.tsx b/frontend/src/routes/router.tsx similarity index 65% rename from frontend/src/router.tsx rename to frontend/src/routes/router.tsx index 0ad49b584..f26b1d68d 100644 --- a/frontend/src/router.tsx +++ b/frontend/src/routes/router.tsx @@ -5,28 +5,45 @@ import { createBrowserRouter } from 'react-router-dom'; import MoimDetailPage from '@_pages/MoimDetailPage/MoimDetailPage'; import ParticipationCompletePage from '@_pages/ParticipationCompletePage/ParticipationCompletePage'; import LoginPage from '@_pages/LoginPage/LoginPage'; +import ProtectedRoute from './ProtectedRoute'; -const router = createBrowserRouter([ +const routesConfig = [ { path: ROUTES.main, element: , + requiresAuth: true, }, { path: ROUTES.addMoim, element: , + requiresAuth: true, }, { path: ROUTES.detail, element: , + requiresAuth: true, }, { path: ROUTES.participationComplete, element: , + requiresAuth: true, }, { path: ROUTES.login, element: , + requiresAuth: false, }, -]); +]; + +const router = createBrowserRouter( + routesConfig.map((route) => ({ + path: route.path, + element: route.requiresAuth ? ( + {route.element} + ) : ( + route.element + ), + })), +); export default router; diff --git a/frontend/src/utils/checkAuthentication.ts b/frontend/src/utils/checkAuthentication.ts new file mode 100644 index 000000000..9a236ac3f --- /dev/null +++ b/frontend/src/utils/checkAuthentication.ts @@ -0,0 +1,5 @@ +import { getToken } from './tokenManager'; + +export const checkAuthentication = () => { + return !!getToken(); +}; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index b2fcaa3cf..bac0a09ee 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -29,7 +29,8 @@ "@_layouts/*": ["src/layouts/*"], "@_pages/*": ["src/pages/*"], "@_types/*": ["src/types/*"], - "@_utils/*": ["src/utils/*"] + "@_utils/*": ["src/utils/*"], + "@_routes/*": ["src/routes/*"] } }, "ts-node": { diff --git a/frontend/webpack.common.js b/frontend/webpack.common.js index 330a15a76..8c9d7fc76 100644 --- a/frontend/webpack.common.js +++ b/frontend/webpack.common.js @@ -38,6 +38,7 @@ module.exports = { '@_pages': path.resolve(__dirname, 'src/pages'), '@_types': path.resolve(__dirname, 'src/types'), '@_utils': path.resolve(__dirname, 'src/utils'), + '@_routes': path.resolve(__dirname, 'src/routes'), }, }, module: { From 60df1dfebf76c2b2415af3a8d93ec55fb9f60bd3 Mon Sep 17 00:00:00 2001 From: cys4585 Date: Thu, 1 Aug 2024 14:10:34 +0900 Subject: [PATCH 08/11] =?UTF-8?q?refactor:=20api=20client=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/apiClient.ts | 210 ++++++++++++---------- frontend/src/apis/auth.ts | 2 +- frontend/src/utils/checkAuthentication.ts | 8 +- frontend/src/utils/tokenManager.ts | 9 +- 4 files changed, 132 insertions(+), 97 deletions(-) diff --git a/frontend/src/apis/apiClient.ts b/frontend/src/apis/apiClient.ts index a186e86a5..05bf8431e 100644 --- a/frontend/src/apis/apiClient.ts +++ b/frontend/src/apis/apiClient.ts @@ -1,57 +1,48 @@ import { getToken } from '@_utils/tokenManager'; -const defaultHeaders = { +type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; + +const DEFAULT_HEADERS = { 'Content-Type': 'application/json', }; -const baseURL = `${process.env.BASE_URL}/v1`; +const BASE_URL = `${process.env.BASE_URL}/v1`; class ApiClient { - private static addBaseURL(url: string) { - if (url[0] !== '/') url = '/' + url; - return baseURL + url; + private static addBaseURL(endpoint: string) { + if (endpoint[0] !== '/') endpoint = '/' + endpoint; + return BASE_URL + endpoint; } - private static getHeaders(token: string | null) { - const headers = new Headers(defaultHeaders); + private static getHeaders(token?: string) { + const headers = new Headers(DEFAULT_HEADERS); if (token) { headers.append('Authorization', `Bearer ${token}`); } return headers; } - static async get(path = '', config = {}, isRequiredAuth = false) { - const url = this.addBaseURL(path); - const token = isRequiredAuth ? getToken() : null; + private static async request( + method: Method, + endpoint: string, + data: object, + config: RequestInit, + isRequiredAuth: boolean = false, + ) { + const url = this.addBaseURL(endpoint); + const token = isRequiredAuth ? getToken() : undefined; - const res = await fetch(url, { - method: 'GET', + const options: RequestInit = { + method, headers: this.getHeaders(token), ...config, - }); + }; - if (!res.ok) { - console.log(res); - throw new Error(res.statusText); + if (method !== 'GET') { + options.body = JSON.stringify(data); } - return res.json(); - } - - static async getWithAuth(path = '', config = {}) { - return this.get(path, config, true); - } - - static async post(path = '', data = {}, config = {}, isRequiredAuth = false) { - const url = this.addBaseURL(path); - const token = isRequiredAuth ? getToken() : null; - - const res = await fetch(url, { - method: 'POST', - headers: this.getHeaders(token), - body: JSON.stringify(data), - ...config, - }); + const res = await fetch(url, options); if (!res.ok) { console.log(res); @@ -63,90 +54,123 @@ class ApiClient { return res.json(); } - return; + return {}; } - static async postWithAuth(path = '', data = {}, config = {}) { - return this.post(path, data, config, true); + static async get( + endpoint: string, + config: RequestInit = {}, + isRequiredAuth: boolean = false, + ) { + return this.request('GET', endpoint, {}, config, isRequiredAuth); } - static async put(path = '', data = {}, config = {}, isRequiredAuth = false) { - const url = this.addBaseURL(path); - const token = isRequiredAuth ? getToken() : null; - - const res = await fetch(url, { - method: 'PUT', - headers: this.getHeaders(token), - body: JSON.stringify(data), - ...config, - }); + static async getWithoutAuth(endpoint: string, config: RequestInit = {}) { + return this.get(endpoint, config, false); + } - if (!res.ok) { - console.log(res); - throw new Error(res.statusText); - } + static async getWithAuth(endpoint: string, config: RequestInit = {}) { + return this.get(endpoint, config, true); + } - return res.json(); + static async post( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + isRequiredAuth: boolean = false, + ) { + return this.request('POST', endpoint, data, config, isRequiredAuth); } - static async putWithAuth(path = '', data = {}, config = {}) { - return this.put(path, data, config, true); + static async postWithAuth( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + ) { + return this.post(endpoint, data, config, true); } - static async patch( - path = '', - data = {}, - config = {}, - isRequiredAuth = false, + static async postWithoutAuth( + endpoint: string, + data: object = {}, + config: RequestInit = {}, ) { - const url = this.addBaseURL(path); - const token = isRequiredAuth ? getToken() : null; + return this.post(endpoint, data, config, false); + } - const res = await fetch(url, { - method: 'patch', - headers: this.getHeaders(token), - body: JSON.stringify(data), - ...config, - }); + static async put( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + isRequiredAuth: boolean = false, + ) { + return this.request('PUT', endpoint, data, config, isRequiredAuth); + } - if (!res.ok) { - console.log(res); - throw new Error(res.statusText); - } + static async putWithAuth( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + ) { + return this.put(endpoint, data, config, true); + } - return res.json(); + static async putWithoutAuth( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + ) { + return this.put(endpoint, data, config, false); } - static async patchWithAuth(path = '', data = {}, config = {}) { - return this.patch(path, data, config, true); + static async patch( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + isRequiredAuth: boolean = false, + ) { + return this.request('PATCH', endpoint, data, config, isRequiredAuth); } - static async delete( - path = '', - data = {}, - config = {}, - isRequiredAuth = false, + static async patchWithAuth( + endpoint: string, + data: object = {}, + config: RequestInit = {}, ) { - const url = this.addBaseURL(path); - const token = isRequiredAuth ? getToken() : null; + return this.patch(endpoint, data, config, true); + } - const res = await fetch(url, { - method: 'DELETE', - headers: this.getHeaders(token), - body: JSON.stringify(data), - ...config, - }); + static async patchWithoutAuth( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + ) { + return this.patch(endpoint, data, config, false); + } - if (!res.ok) { - console.log(res); - throw new Error(res.statusText); - } + static async delete( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + isRequiredAuth: boolean = false, + ) { + return this.request('DELETE', endpoint, data, config, isRequiredAuth); + } - return res.json(); + static async deleteWithAuth( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + ) { + return this.delete(endpoint, data, config, true); } - static async deleteWithAuth(path = '', data = {}, config = {}) { - return this.delete(path, data, config, true); + static async deleteWithoutAuth( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + ) { + return this.delete(endpoint, data, config, false); } } diff --git a/frontend/src/apis/auth.ts b/frontend/src/apis/auth.ts index 4a473739d..bc1a13d06 100644 --- a/frontend/src/apis/auth.ts +++ b/frontend/src/apis/auth.ts @@ -1,5 +1,5 @@ import ApiClient from './apiClient'; export const login = async (loginInputInfo: { nickname: string }) => { - return await ApiClient.post('auth/login', loginInputInfo); + return await ApiClient.postWithoutAuth('auth/login', loginInputInfo); }; diff --git a/frontend/src/utils/checkAuthentication.ts b/frontend/src/utils/checkAuthentication.ts index 9a236ac3f..9b7e6bb85 100644 --- a/frontend/src/utils/checkAuthentication.ts +++ b/frontend/src/utils/checkAuthentication.ts @@ -1,5 +1,11 @@ import { getToken } from './tokenManager'; +// TODO: 정확한 auth 검증 필요 (지금은 token이 localstorage에 있어도 만료여부를 모름) export const checkAuthentication = () => { - return !!getToken(); + try { + getToken(); + return true; + } catch (error) { + return false; + } }; diff --git a/frontend/src/utils/tokenManager.ts b/frontend/src/utils/tokenManager.ts index 484c4cf3a..8f6e34e99 100644 --- a/frontend/src/utils/tokenManager.ts +++ b/frontend/src/utils/tokenManager.ts @@ -4,8 +4,13 @@ export const setToken = (token: string): void => { localStorage.setItem(TOKEN_KEY, token); }; -export const getToken = (): string | null => { - return localStorage.getItem(TOKEN_KEY); +// TODO: token 관리 로직 추가 필요(토큰 존재, 토큰 만료) +export const getToken = (): string => { + const token = localStorage.getItem(TOKEN_KEY); + if (token === null) { + throw new Error('로컬 스토리지에 토큰이 없습니다.'); + } + return token; }; export const removeToken = (): void => { From c81d1030b86f96378c39ea85564bbd5eb3a0a409 Mon Sep 17 00:00:00 2001 From: cys4585 Date: Thu, 1 Aug 2024 15:29:43 +0900 Subject: [PATCH 09/11] =?UTF-8?q?feature:=20api=20client=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EC=97=90=EB=9F=AC=20=ED=95=B8=EB=93=A4=EB=A7=81=EC=9D=84=20?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EA=B3=A0,=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=B2=98=EC=97=90=EC=84=9C=20=EC=9C=A0=EC=97=B0=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20API=20=EC=97=90=EB=9F=AC=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=A7=81=ED=95=98=EB=8F=84=EB=A1=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/apiClient.ts | 28 ++++++++-------------------- frontend/src/apis/auth.ts | 8 +++++++- frontend/src/apis/gets.ts | 12 ++++++++++-- frontend/src/apis/posts.ts | 14 ++++++++++++-- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/frontend/src/apis/apiClient.ts b/frontend/src/apis/apiClient.ts index 05bf8431e..402bc58ed 100644 --- a/frontend/src/apis/apiClient.ts +++ b/frontend/src/apis/apiClient.ts @@ -25,8 +25,8 @@ class ApiClient { private static async request( method: Method, endpoint: string, - data: object, - config: RequestInit, + data: object = {}, + config: RequestInit = {}, isRequiredAuth: boolean = false, ) { const url = this.addBaseURL(endpoint); @@ -42,22 +42,10 @@ class ApiClient { options.body = JSON.stringify(data); } - const res = await fetch(url, options); - - if (!res.ok) { - console.log(res); - throw new Error(res.statusText); - } - - const contentType = res.headers.get('Content-Type'); - if (contentType && contentType.includes('application/json')) { - return res.json(); - } - - return {}; + return await fetch(url, options); } - static async get( + private static async get( endpoint: string, config: RequestInit = {}, isRequiredAuth: boolean = false, @@ -73,7 +61,7 @@ class ApiClient { return this.get(endpoint, config, true); } - static async post( + private static async post( endpoint: string, data: object = {}, config: RequestInit = {}, @@ -98,7 +86,7 @@ class ApiClient { return this.post(endpoint, data, config, false); } - static async put( + private static async put( endpoint: string, data: object = {}, config: RequestInit = {}, @@ -123,7 +111,7 @@ class ApiClient { return this.put(endpoint, data, config, false); } - static async patch( + private static async patch( endpoint: string, data: object = {}, config: RequestInit = {}, @@ -148,7 +136,7 @@ class ApiClient { return this.patch(endpoint, data, config, false); } - static async delete( + private static async delete( endpoint: string, data: object = {}, config: RequestInit = {}, diff --git a/frontend/src/apis/auth.ts b/frontend/src/apis/auth.ts index bc1a13d06..db37d8970 100644 --- a/frontend/src/apis/auth.ts +++ b/frontend/src/apis/auth.ts @@ -1,5 +1,11 @@ import ApiClient from './apiClient'; +import { checkStatus } from './apiconfig'; export const login = async (loginInputInfo: { nickname: string }) => { - return await ApiClient.postWithoutAuth('auth/login', loginInputInfo); + const response = await ApiClient.postWithoutAuth( + 'auth/login', + loginInputInfo, + ); + checkStatus(response); + return response.json(); }; diff --git a/frontend/src/apis/gets.ts b/frontend/src/apis/gets.ts index 52c56b98b..6f42a8c51 100644 --- a/frontend/src/apis/gets.ts +++ b/frontend/src/apis/gets.ts @@ -2,12 +2,20 @@ import { MoimInfo } from '@_types/index'; import ApiClient from './apiClient'; import { GetMoim, GetMoims } from './responseTypes'; +import { checkStatus } from './apiconfig'; export const getMoims = async (): Promise => { - const json: GetMoims = await ApiClient.getWithAuth('moim'); + const response = await ApiClient.getWithAuth('moim'); + checkStatus(response); + + const json: GetMoims = await response.json(); return json.data.moims; }; + export const getMoim = async (moimId: number): Promise => { - const json: GetMoim = await ApiClient.getWithAuth(`moim/${moimId}`); + const response = await ApiClient.getWithAuth(`moim/${moimId}`); + checkStatus(response); + + const json: GetMoim = await response.json(); return json.data; }; diff --git a/frontend/src/apis/posts.ts b/frontend/src/apis/posts.ts index 0ab8d77e3..b5ae12be3 100644 --- a/frontend/src/apis/posts.ts +++ b/frontend/src/apis/posts.ts @@ -1,11 +1,21 @@ import { MoimInputInfo } from '@_types/index'; import ApiClient from './apiClient'; +import { PostMoim } from './responseTypes'; +import { checkStatus } from './apiconfig'; export const postMoim = async (moim: MoimInputInfo): Promise => { - const json = await ApiClient.postWithAuth('moim', moim); + const response = await ApiClient.postWithAuth('moim', moim); + + checkStatus(response); + + const json: PostMoim = await response.json(); return json.data; }; export const postJoinMoim = async (moimId: number, nickname: string) => { - await ApiClient.postWithAuth('moim/join', { moimId, nickname }); + const response = await ApiClient.postWithAuth('moim/join', { + moimId, + nickname, + }); + await checkStatus(response); }; From 80732feeb2bb60d8a4c847bb12848440350b39f1 Mon Sep 17 00:00:00 2001 From: cys4585 Date: Thu, 1 Aug 2024 15:41:14 +0900 Subject: [PATCH 10/11] =?UTF-8?q?refactor:=20ApiClient=20=EB=A6=AC?= =?UTF-8?q?=ED=84=B0=EB=9F=B4=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/apiClient.ts | 206 ++++++++++++++++----------------- 1 file changed, 102 insertions(+), 104 deletions(-) diff --git a/frontend/src/apis/apiClient.ts b/frontend/src/apis/apiClient.ts index 402bc58ed..c6681f88f 100644 --- a/frontend/src/apis/apiClient.ts +++ b/frontend/src/apis/apiClient.ts @@ -8,158 +8,156 @@ const DEFAULT_HEADERS = { const BASE_URL = `${process.env.BASE_URL}/v1`; -class ApiClient { - private static addBaseURL(endpoint: string) { - if (endpoint[0] !== '/') endpoint = '/' + endpoint; - return BASE_URL + endpoint; - } +function addBaseURL(endpoint: string) { + if (endpoint[0] !== '/') endpoint = '/' + endpoint; + return BASE_URL + endpoint; +} - private static getHeaders(token?: string) { - const headers = new Headers(DEFAULT_HEADERS); - if (token) { - headers.append('Authorization', `Bearer ${token}`); - } - return headers; +function getHeaders(token?: string) { + const headers = new Headers(DEFAULT_HEADERS); + if (token) { + headers.append('Authorization', `Bearer ${token}`); } + return headers; +} - private static async request( - method: Method, - endpoint: string, - data: object = {}, - config: RequestInit = {}, - isRequiredAuth: boolean = false, - ) { - const url = this.addBaseURL(endpoint); - const token = isRequiredAuth ? getToken() : undefined; - - const options: RequestInit = { - method, - headers: this.getHeaders(token), - ...config, - }; +async function request( + method: Method, + endpoint: string, + data: object = {}, + config: RequestInit = {}, + isRequiredAuth: boolean = false, +) { + const url = addBaseURL(endpoint); + const token = isRequiredAuth ? getToken() : undefined; - if (method !== 'GET') { - options.body = JSON.stringify(data); - } + const options: RequestInit = { + method, + headers: getHeaders(token), + ...config, + }; - return await fetch(url, options); + if (method !== 'GET') { + options.body = JSON.stringify(data); } - private static async get( - endpoint: string, - config: RequestInit = {}, - isRequiredAuth: boolean = false, - ) { - return this.request('GET', endpoint, {}, config, isRequiredAuth); - } + return await fetch(url, options); +} - static async getWithoutAuth(endpoint: string, config: RequestInit = {}) { - return this.get(endpoint, config, false); - } +async function get( + endpoint: string, + config: RequestInit = {}, + isRequiredAuth: boolean = false, +) { + return request('GET', endpoint, {}, config, isRequiredAuth); +} - static async getWithAuth(endpoint: string, config: RequestInit = {}) { - return this.get(endpoint, config, true); - } +async function post( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + isRequiredAuth: boolean = false, +) { + return request('POST', endpoint, data, config, isRequiredAuth); +} - private static async post( - endpoint: string, - data: object = {}, - config: RequestInit = {}, - isRequiredAuth: boolean = false, - ) { - return this.request('POST', endpoint, data, config, isRequiredAuth); - } +async function put( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + isRequiredAuth: boolean = false, +) { + return request('PUT', endpoint, data, config, isRequiredAuth); +} - static async postWithAuth( - endpoint: string, - data: object = {}, - config: RequestInit = {}, - ) { - return this.post(endpoint, data, config, true); - } +async function patch( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + isRequiredAuth: boolean = false, +) { + return request('PATCH', endpoint, data, config, isRequiredAuth); +} - static async postWithoutAuth( - endpoint: string, - data: object = {}, - config: RequestInit = {}, - ) { - return this.post(endpoint, data, config, false); - } +/** + * delete는 예약어로 사용할 수 없는 함수 이름이라 부득이 `deleteMethod`로 이름을 지었습니다. + */ +async function deleteMethod( + endpoint: string, + data: object = {}, + config: RequestInit = {}, + isRequiredAuth: boolean = false, +) { + return request('DELETE', endpoint, data, config, isRequiredAuth); +} - private static async put( - endpoint: string, - data: object = {}, - config: RequestInit = {}, - isRequiredAuth: boolean = false, - ) { - return this.request('PUT', endpoint, data, config, isRequiredAuth); - } +const ApiClient = { + async getWithoutAuth(endpoint: string, config: RequestInit = {}) { + return get(endpoint, config, false); + }, + async getWithAuth(endpoint: string, config: RequestInit = {}) { + return get(endpoint, config, true); + }, - static async putWithAuth( + async postWithAuth( endpoint: string, data: object = {}, config: RequestInit = {}, ) { - return this.put(endpoint, data, config, true); - } - - static async putWithoutAuth( + return post(endpoint, data, config, true); + }, + async postWithoutAuth( endpoint: string, data: object = {}, config: RequestInit = {}, ) { - return this.put(endpoint, data, config, false); - } + return post(endpoint, data, config, false); + }, - private static async patch( + async putWithAuth( endpoint: string, data: object = {}, config: RequestInit = {}, - isRequiredAuth: boolean = false, ) { - return this.request('PATCH', endpoint, data, config, isRequiredAuth); - } - - static async patchWithAuth( + return put(endpoint, data, config, true); + }, + async putWithoutAuth( endpoint: string, data: object = {}, config: RequestInit = {}, ) { - return this.patch(endpoint, data, config, true); - } + return put(endpoint, data, config, false); + }, - static async patchWithoutAuth( + async patchWithAuth( endpoint: string, data: object = {}, config: RequestInit = {}, ) { - return this.patch(endpoint, data, config, false); - } - - private static async delete( + return patch(endpoint, data, config, true); + }, + async patchWithoutAuth( endpoint: string, data: object = {}, config: RequestInit = {}, - isRequiredAuth: boolean = false, ) { - return this.request('DELETE', endpoint, data, config, isRequiredAuth); - } + return patch(endpoint, data, config, false); + }, - static async deleteWithAuth( + async deleteWithAuth( endpoint: string, data: object = {}, config: RequestInit = {}, ) { - return this.delete(endpoint, data, config, true); - } - - static async deleteWithoutAuth( + return deleteMethod(endpoint, data, config, true); + }, + async deleteWithoutAuth( endpoint: string, data: object = {}, config: RequestInit = {}, ) { - return this.delete(endpoint, data, config, false); - } -} + return deleteMethod(endpoint, data, config, false); + }, +}; export default ApiClient; From 32cebc24ac24215ab74ca0af5943463f899e9c58 Mon Sep 17 00:00:00 2001 From: cys4585 Date: Thu, 1 Aug 2024 15:49:29 +0900 Subject: [PATCH 11/11] =?UTF-8?q?style:=20addBaseUrl=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/apiClient.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/apis/apiClient.ts b/frontend/src/apis/apiClient.ts index c6681f88f..814397561 100644 --- a/frontend/src/apis/apiClient.ts +++ b/frontend/src/apis/apiClient.ts @@ -8,7 +8,7 @@ const DEFAULT_HEADERS = { const BASE_URL = `${process.env.BASE_URL}/v1`; -function addBaseURL(endpoint: string) { +function addBaseUrl(endpoint: string) { if (endpoint[0] !== '/') endpoint = '/' + endpoint; return BASE_URL + endpoint; } @@ -28,7 +28,7 @@ async function request( config: RequestInit = {}, isRequiredAuth: boolean = false, ) { - const url = addBaseURL(endpoint); + const url = addBaseUrl(endpoint); const token = isRequiredAuth ? getToken() : undefined; const options: RequestInit = {