diff --git a/src/pages/search/SearchPage.tsx b/src/pages/search/SearchPage.tsx index ccff7daa..a1dd97ed 100644 --- a/src/pages/search/SearchPage.tsx +++ b/src/pages/search/SearchPage.tsx @@ -1,11 +1,10 @@ -// SearchPage.tsx import { useEffect, useMemo, useState } from 'react'; import { Link, useSearchParams } from 'react-router-dom'; import type { SemanticArticle } from '@/pages/search/types/searchTypes'; import LoadingFallback from '@/routes/LoadingFallback'; -import { isSemanticSearchApiError, semanticSearch } from './apis/searchApi'; +import { semanticSearch } from './apis/searchApi'; const MIN_LENGTH_MESSAGE = '검색어는 두 글자 이상이어야 합니다.'; const EMPTY_RESULT_MESSAGE = '검색 결과가 없습니다.'; @@ -44,32 +43,28 @@ const SearchPage = () => { setLoading(true); setShowLengthPopup(false); setError(null); - console.log('[SearchPage] runSearch:start', { q, page, size, threshold }); try { const result = await semanticSearch({ query: q, page, size, threshold }); + setArticles(result.articles ?? []); + } catch (e: any) { + const status = e?.response?.status; + const message = e?.response?.data?.message; - console.log('[SearchPage] runSearch:done', { - q_from_url: q, - q_in_result: result.query, - articles_len: result.articles.length, - totalCount: result.totalCount, - }); - - setArticles(result.articles); - } catch (e) { - console.log('[SearchPage] runSearch:error', e); - setShowLengthPopup(false); - if (isSemanticSearchApiError(e) && e.code === 'FEED_9606') { - setError(EMPTY_RESULT_MESSAGE); - setArticles(e.payload?.articles ?? []); - } else if (e instanceof Error) { - setError(e.message || '검색 결과가 없습니다.'); + if (status === 204) { setArticles([]); - } else { - setError('검색 결과가 없습니다.'); + setError(null); + return; + } + + if (status === 400 && message?.includes('유효한 검색어')) { + setError('유효한 검색어가 없습니다. 의미 있는 단어를 입력하세요.'); setArticles([]); + return; } + + setError('검색 중 오류가 발생했습니다.'); + setArticles([]); } finally { setLoading(false); } @@ -100,7 +95,7 @@ const SearchPage = () => { {loading && } {error &&
{error}
} {!loading && !error && articles.length === 0 && ( -
검색 결과가 없습니다.
+
{EMPTY_RESULT_MESSAGE}
)} {!loading && !error && diff --git a/src/shared/apis/api.ts b/src/shared/apis/api.ts index 8714f361..bc9e5693 100644 --- a/src/shared/apis/api.ts +++ b/src/shared/apis/api.ts @@ -3,91 +3,58 @@ import type { AxiosResponse } from 'axios'; import type { ApiRequestOptionsTypes, ApiResponseTypes } from '../types/apiTypes'; import axiosInstance from './axios'; -/** - * 기본 API 객체 - * - * 사용 예시: - * - GET: api.get('/users') - * - POST: api.post('/users', userData) - * - PUT: api.put('/users/1', userData) - * - DELETE: api.delete('/users/1') - */ +function extract(response: AxiosResponse): T { + if (response.status === 204 || response.data == null || response.data === '') { + return undefined as T; + } + const data = response.data as ApiResponseTypes; + if (!data.isSuccess) { + throw new Error(data.message || 'API 요청 실패'); + } + return data.result as T; +} + const api = { - /** - * GET 요청 - */ get: async (url: string, options?: ApiRequestOptionsTypes): Promise => { - const response: AxiosResponse> = await axiosInstance.get(url, { + const res = await axiosInstance.get(url, { params: options?.params, headers: options?.headers, timeout: options?.timeout, }); - if (!response.data.isSuccess) { - throw new Error(response.data.message || 'API 요청 실패'); - } - - return response.data.result as T; + return extract(res); }, - /** - * POST 요청 - */ post: async (url: string, data?: unknown, options?: ApiRequestOptionsTypes): Promise => { - const response: AxiosResponse> = await axiosInstance.post(url, data, { + const res = await axiosInstance.post(url, data, { headers: options?.headers, timeout: options?.timeout, }); - if (!response.data.isSuccess) { - throw new Error(response.data.message || 'API 요청 실패'); - } - - return response.data.result as T; + return extract(res); }, - /** - * PUT 요청 - */ put: async (url: string, data?: unknown, options?: ApiRequestOptionsTypes): Promise => { - const response: AxiosResponse> = await axiosInstance.put(url, data, { + const res = await axiosInstance.put(url, data, { headers: options?.headers, timeout: options?.timeout, }); - if (!response.data.isSuccess) { - throw new Error(response.data.message || 'API 요청 실패'); - } - - return response.data.result as T; + return extract(res); }, - /** - * PATCH 요청 - */ patch: async (url: string, data?: unknown, options?: ApiRequestOptionsTypes): Promise => { - const response: AxiosResponse> = await axiosInstance.patch(url, data, { + const res = await axiosInstance.patch(url, data, { headers: options?.headers, timeout: options?.timeout, }); - if (!response.data.isSuccess) { - throw new Error(response.data.message || 'API 요청 실패'); - } - - return response.data.result as T; + return extract(res); }, - /** - * DELETE 요청 - */ delete: async (url: string, options?: ApiRequestOptionsTypes): Promise => { - const response: AxiosResponse> = await axiosInstance.delete(url, { + const res = await axiosInstance.delete(url, { params: options?.params, headers: options?.headers, timeout: options?.timeout, }); - if (!response.data.isSuccess) { - throw new Error(response.data.message || 'API 요청 실패'); - } - - return response.data.result as T; + return extract(res); }, };