Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions src/_apis/auth/auth-apis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,36 @@ import { fetchApi } from '@/src/utils/api';
import { LoginRequest, LoginResponse, SignupRequest, SignupResponse, User } from '@/src/types/auth';

export function signupUser(data: SignupRequest): Promise<{ data: SignupResponse }> {
return fetchApi<{ data: SignupResponse; headers: Headers }>('/auths/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
return fetchApi<{ data: SignupResponse; headers: Headers }>(
'/auths/signup',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
},
body: JSON.stringify(data),
}).then((response) => {
5000,
true,
).then((response) => {
Comment on lines +5 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

μ—λŸ¬ 처리 둜직이 ν•„μš”ν•©λ‹ˆλ‹€

둜그인과 νšŒμ›κ°€μž… ν•¨μˆ˜μ—μ„œ λ„€νŠΈμ›Œν¬ 였λ₯˜λ‚˜ μ„œλ²„ 였λ₯˜μ— λŒ€ν•œ μ²˜λ¦¬κ°€ λˆ„λ½λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. μ‚¬μš©μžμ—κ²Œ μ μ ˆν•œ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό μ œκ³΅ν•˜κΈ° μœ„ν•΄ μ—λŸ¬ 처리λ₯Ό μΆ”κ°€ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 μ—λŸ¬ 처리 λ‘œμ§μ„ μΆ”κ°€ν•˜λŠ” 것을 μ œμ•ˆν•©λ‹ˆλ‹€:

 export function signupUser(data: SignupRequest): Promise<{ data: SignupResponse }> {
   return fetchApi<{ data: SignupResponse; headers: Headers }>(
     '/auths/signup',
     {
       method: 'POST',
       headers: {
         'Content-Type': 'application/json',
       },
       body: JSON.stringify(data),
     },
     5000,
     true,
-  ).then((response) => {
+  ).then((response) => {
     const token = response.headers.get('Authorization');
+    if (!token) {
+      throw new Error('인증 토큰을 λ°›μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€');
+    }
     return { data: { token } };
+  }).catch((error) => {
+    if (error.status === 409) {
+      throw new Error('이미 μ‘΄μž¬ν•˜λŠ” μ‚¬μš©μžμž…λ‹ˆλ‹€');
+    }
+    throw new Error('νšŒμ›κ°€μž… 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€');
   });
 }

Also applies to: 23-34


πŸ› οΈ Refactor suggestion

쀑볡 μ½”λ“œλ₯Ό μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜λ‘œ λΆ„λ¦¬ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€

signupUser와 loginUser ν•¨μˆ˜μ˜ ꡬ쑰가 맀우 μœ μ‚¬ν•©λ‹ˆλ‹€. μ½”λ“œ 쀑볡을 쀄이고 μœ μ§€λ³΄μˆ˜μ„±μ„ 높이기 μœ„ν•΄ 곡톡 λ‘œμ§μ„ λ³„λ„μ˜ μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜λ‘œ λΆ„λ¦¬ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 λ¦¬νŒ©ν† λ§ν•˜λŠ” 것을 μ œμ•ˆν•©λ‹ˆλ‹€:

+const handleAuthRequest = async <T>(
+  endpoint: string,
+  data: any
+): Promise<{ data: T }> => {
+  const response = await fetchApi<{ data: T; headers: Headers }>(
+    endpoint,
+    {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify(data),
+    },
+    5000,
+    true
+  );
+  
+  const token = response.headers.get('Authorization');
+  if (!token) {
+    throw new Error('인증 토큰을 λ°›μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€');
+  }
+  return { data: { token } as T };
+};

 export function signupUser(data: SignupRequest): Promise<{ data: SignupResponse }> {
-  return fetchApi<{ data: SignupResponse; headers: Headers }>(
-    '/auths/signup',
-    {
-      method: 'POST',
-      headers: {
-        'Content-Type': 'application/json',
-      },
-      body: JSON.stringify(data),
-    },
-    5000,
-    true,
-  ).then((response) => {
-    const token = response.headers.get('Authorization');
-    return { data: { token } };
-  });
+  return handleAuthRequest<SignupResponse>('/auths/signup', data);
 }

 export function loginUser(data: LoginRequest): Promise<{ data: LoginResponse }> {
-  return fetchApi<{ data: LoginResponse; headers: Headers }>(
-    '/auths/login',
-    {
-      method: 'POST',
-      headers: {
-        'Content-Type': 'application/json',
-      },
-      body: JSON.stringify(data),
-    },
-    5000,
-    true,
-  ).then((response) => {
-    const token = response.headers.get('Authorization');
-    return { data: { token } };
-  });
+  return handleAuthRequest<LoginResponse>('/auths/login', data);
 }

Also applies to: 23-34

const token = response.headers.get('Authorization');
return { data: { token } };
});
}

export function loginUser(data: LoginRequest): Promise<{ data: LoginResponse }> {
return fetchApi<{ data: LoginResponse; headers: Headers }>('/auths/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
return fetchApi<{ data: LoginResponse; headers: Headers }>(
'/auths/login',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
},
body: JSON.stringify(data),
}).then((response) => {
5000,
true,
).then((response) => {
const token = response.headers.get('Authorization');
return { data: { token } };
});
Expand Down
5 changes: 3 additions & 2 deletions src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export async function fetchApi<T>(
url: string,
options: RequestInit = {},
timeout = 5000,
isAuth = false,
): Promise<T> {
const controller = new AbortController();
const { signal } = controller;
Expand Down Expand Up @@ -49,9 +50,9 @@ export async function fetchApi<T>(

throw new ApiError(response.status, errorMessage, errorDetail);
}

const data = await response.json();
return { ...data, headers: response.headers } as T;
if (isAuth) return { data, headers: response.headers } as T;
return { data } as T;
Comment on lines +54 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

λ°˜ν™˜ νƒ€μž… μ²˜λ¦¬μ— λŒ€ν•œ κ°œμ„ μ΄ ν•„μš”ν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 λ¬Έμ œμ λ“€μ΄ μžˆμŠ΅λ‹ˆλ‹€:

  1. 쑰건뢀 λ°˜ν™˜ νƒ€μž…μœΌλ‘œ 인해 νƒ€μž… μ•ˆμ „μ„±μ΄ μ €ν•˜λ  수 μžˆμŠ΅λ‹ˆλ‹€.
  2. 인증에 ν•„μš”ν•œ ν•„μˆ˜ ν—€λ”μ˜ 쑴재 μ—¬λΆ€λ₯Ό ν™•μΈν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 κ°œμ„ μ„ μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

interface AuthResponse<T> {
  data: T;
  headers: Headers;
}

interface DataResponse<T> {
  data: T;
}

export async function fetchApi<T>(
  url: string,
  options: RequestInit = {},
  timeout = 5000,
  includeHeaders = false,
): Promise<AuthResponse<T> | DataResponse<T>> {
  // ... existing code ...
  
  if (includeHeaders) {
    const requiredHeaders = ['authorization', 'content-type'];
    const missingHeaders = requiredHeaders.filter(
      header => !response.headers.has(header)
    );
    
    if (missingHeaders.length > 0) {
      throw new ApiError(
        500,
        `Missing required headers: ${missingHeaders.join(', ')}`
      );
    }
    
    return { data, headers: response.headers } as AuthResponse<T>;
  }
  
  return { data } as DataResponse<T>;
}

} catch (error) {
if (error instanceof Error) {
if (error.name === 'AbortError') throw new ApiError(408, 'Request timeout');
Expand Down