From 2b1eaf4431d089dec3ed657530511fd1850d0ff7 Mon Sep 17 00:00:00 2001 From: saseungmin Date: Sun, 8 Sep 2024 20:41:39 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EA=B3=B5=ED=86=B5=20api=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=97=90=EB=9F=AC=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/auth/callback/kakao/route.ts | 13 ++-- src/app/api/my/favorite-places/route.ts | 12 ++-- src/app/api/search/nearby/places/route.ts | 12 ++-- src/app/api/search/places/[placeId]/route.ts | 12 ++-- src/app/api/search/places/route.ts | 12 ++-- src/lib/apis/index.ts | 73 +++++++++++--------- src/lib/types/api.ts | 2 +- 7 files changed, 84 insertions(+), 52 deletions(-) diff --git a/src/app/api/auth/callback/kakao/route.ts b/src/app/api/auth/callback/kakao/route.ts index 7568ff13..738450c7 100644 --- a/src/app/api/auth/callback/kakao/route.ts +++ b/src/app/api/auth/callback/kakao/route.ts @@ -48,12 +48,17 @@ export async function POST(request: NextRequest) { }); return response; - } catch (error: any) { - const errorResponse = error as FetchError; + } catch (error) { + if (error instanceof FetchError) { + return NextResponse.json(null, { + status: error.status, + statusText: error.message, + }); + } return NextResponse.json(null, { - status: errorResponse.response?.status, - statusText: errorResponse.message, + status: 500, + statusText: 'Internal Server Error', }); } } diff --git a/src/app/api/my/favorite-places/route.ts b/src/app/api/my/favorite-places/route.ts index e506ce2b..6ccce1f3 100644 --- a/src/app/api/my/favorite-places/route.ts +++ b/src/app/api/my/favorite-places/route.ts @@ -69,12 +69,16 @@ export async function GET(request: NextRequest) { items: favoritePlaces, }); } catch (error) { - const fetchError = error as FetchError; + if (error instanceof FetchError) { + return NextResponse.json(null, { + status: error.status, + statusText: error.message, + }); + } return NextResponse.json(null, { - status: fetchError.response?.status || 500, - statusText: fetchError.response?.statusText || fetchError.message, - headers: fetchError.response?.headers, + status: 500, + statusText: 'Internal Server Error', }); } } diff --git a/src/app/api/search/nearby/places/route.ts b/src/app/api/search/nearby/places/route.ts index eaa09b5b..a2cbcfd0 100644 --- a/src/app/api/search/nearby/places/route.ts +++ b/src/app/api/search/nearby/places/route.ts @@ -52,12 +52,16 @@ export async function GET(request: NextRequest) { status: 200, }); } catch (error) { - const fetchError = error as FetchError; + if (error instanceof FetchError) { + return NextResponse.json(null, { + status: error.status, + statusText: error.message, + }); + } return NextResponse.json(null, { - status: fetchError.response?.status, - statusText: fetchError.response?.statusText, - headers: fetchError.response?.headers, + status: 500, + statusText: 'internal server error', }); } } diff --git a/src/app/api/search/places/[placeId]/route.ts b/src/app/api/search/places/[placeId]/route.ts index dd1a5261..3d18ad81 100644 --- a/src/app/api/search/places/[placeId]/route.ts +++ b/src/app/api/search/places/[placeId]/route.ts @@ -87,12 +87,16 @@ export async function GET(request: NextRequest) { }, }); } catch (error) { - const fetchError = error as FetchError; + if (error instanceof FetchError) { + return NextResponse.json(null, { + status: error.status, + statusText: error.message, + }); + } return NextResponse.json(null, { - status: fetchError.response?.status || 500, - statusText: fetchError.response?.statusText || fetchError.message, - headers: fetchError.response?.headers, + status: 500, + statusText: 'internal server error', }); } } diff --git a/src/app/api/search/places/route.ts b/src/app/api/search/places/route.ts index 8f977183..73858fe0 100644 --- a/src/app/api/search/places/route.ts +++ b/src/app/api/search/places/route.ts @@ -57,12 +57,16 @@ export async function GET(request: NextRequest) { status: 200, }); } catch (error) { - const fetchError = error as FetchError; + if (error instanceof FetchError) { + return NextResponse.json(null, { + status: error.status, + statusText: error.message, + }); + } return NextResponse.json(null, { - status: fetchError.response?.status, - statusText: fetchError.response?.statusText, - headers: fetchError.response?.headers, + status: 500, + statusText: 'internal server error', }); } } diff --git a/src/lib/apis/index.ts b/src/lib/apis/index.ts index a5405231..f34a93db 100644 --- a/src/lib/apis/index.ts +++ b/src/lib/apis/index.ts @@ -3,16 +3,10 @@ import qs from 'qs'; import { FetchRequest, UrlPrefixType } from '../types/api'; export class FetchError extends Error { - constructor( - response: Response, - errorMessage = '', - ) { - super(); - this.response = response; - this.message = errorMessage; + constructor(public status: number, message: string) { + super(message); + this.name = 'FetchError'; } - - response?: Response; } export const paramsSerializer = (params: T): string => qs.stringify(params, { @@ -32,39 +26,56 @@ export const getUrl = (url: string, type: UrlPrefixType) => { return `${process.env.NEXT_PUBLIC_API_HOST}${url}`; }; -async function api({ +async function api({ url, params, config = {}, headers, type = 'public', method = 'GET', }: FetchRequest): Promise { - const defaultHeader = type === 'public' ? { 'nfteam-api-token': process.env.API_HEADER_TOKEN } : undefined; + const defaultHeader = new Headers(headers); + + if (type === 'public') { + defaultHeader.set('nfteam-api-token', process.env.API_HEADER_TOKEN); + } + const googleKey = type === 'google' ? { key: process.env.NEXT_PUBLIC_GOOGLE_MAP_API_KEY } : undefined; - const response = await fetch(`${getUrl(url, type)}?${paramsSerializer({ + const defaultParams = paramsSerializer({ ...params, ...googleKey, - })}`, { - ...config, - headers: { - ...defaultHeader, - ...headers, - ...(config?.body ? { - Accept: 'application/json', - 'Content-Type': 'application/json', - } : {}), - }, - method, }); - if (!response.ok) { - throw new FetchError(response, response.statusText); - } + try { + const response = await fetch(`${getUrl(url, type)}${defaultParams ? `?${defaultParams}` : ''}`, { + headers: { + ...defaultHeader, + ...headers, + ...(config?.body ? { + Accept: 'application/json', + 'Content-Type': 'application/json', + } : {}), + }, + method, + ...config, + }); - if (response.status === 204) { - return null as T; - } + if (!response.ok) { + const errorBody = await response.json().catch(() => ({})); + + throw new FetchError(response.status, errorBody?.message || response.statusText); + } + + if (response.status === 204) { + return null as T; + } - const data = await response.json() as Promise; + const data = await response.json() as T; - return data; + return data; + } catch (error) { + if (error instanceof FetchError) { + throw error; + } + + throw new FetchError(500, 'An unexpected error occurred'); + } } export default api; diff --git a/src/lib/types/api.ts b/src/lib/types/api.ts index fb5e88e8..953b14fb 100644 --- a/src/lib/types/api.ts +++ b/src/lib/types/api.ts @@ -12,7 +12,7 @@ type Method = export type UrlPrefixType = 'public' | 'google' | 'bff'; -export interface FetchRequest { +export interface FetchRequest { url: string; params?: T; method?: Method;