Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 32x 32x 32x 32x 32x 32x 32x 32x 32x 32x 32x 32x 1x 1x 1x 31x 31x 1x 1x 1x 1x 1x 1x 1x 18x 18x 27x 27x 27x 18x 18x 2x 2x 2x 18x 18x 18x 18x 1x 1x 1x 18x 18x 2x 1x 1x 18x 1x 1x 1x 1x | import axios from 'axios';
import { CommonErrorResponse, CommonSuccessResponse } from '@/types/service/common';
import { API } from '..';
export const baseAPI = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_BASE_URL,
timeout: 20000,
});
baseAPI.interceptors.request.use(async (config) => {
const isServer = typeof window === 'undefined';
if (isServer) {
// // Server 환경
const { cookies } = await import('next/headers');
const cookieStore = await cookies();
const token = cookieStore.get('accessToken')?.value;
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
} else {
// Client 환경
const match = document.cookie.match(new RegExp('(^| )accessToken=([^;]+)'));
const token = match ? decodeURIComponent(match[2]) : undefined;
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
}
return config;
});
baseAPI.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
const errorResponse: CommonErrorResponse = error.response?.data || {
type: 'about:blank',
title: 'Network Error',
status: 0,
detail: '서버와 연결할 수 없습니다.',
instance: error.config?.url || '',
errorCode: 'NETWORK_ERROR',
};
const status = error.response?.status ?? errorResponse.status;
const isServer = typeof window === 'undefined';
const originalRequest = error.config;
// skipAuthRedirect flag가 지정되어있지 않으면 항상 redirect 되도록
if (originalRequest.skipAuthRedirect === undefined) {
originalRequest.skipAuthRedirect = true;
}
if (status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
// refresh - set cookie는 클라이언트 요청만 동작함
if (!isServer) {
await API.authService.refresh(originalRequest.skipAuthRedirect);
}
return baseAPI(originalRequest);
} catch (refreshError) {
if (!originalRequest.skipAuthRedirect) throw refreshError;
if (isServer) {
const { redirect } = await import('next/navigation');
redirect('/login');
} else {
if (window.location.pathname === '/login') {
throw errorResponse;
}
const currentPath = window.location.pathname + window.location.search;
window.location.href = `/login?error=unauthorized&path=${encodeURIComponent(currentPath)}`;
}
}
}
if (status === 404) {
if (isServer) {
const { notFound } = await import('next/navigation');
notFound();
}
}
throw errorResponse;
},
);
type ApiVersionType = 'v1' | 'v2';
// 공통 응답 형식 처리를 위한 api 헬퍼
const apiHelper = (v: ApiVersionType = 'v1') => ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get: async <T>(url: string, config?: any): Promise<T> => {
const response = await baseAPI.get<CommonSuccessResponse<T>>(`/api/${v}${url}`, config);
return response.data.data;
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
post: async <T>(url: string, data?: any, config?: any): Promise<T> => {
const response = await baseAPI.post<CommonSuccessResponse<T>>(`/api/${v}${url}`, data, config);
return response.data.data;
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
put: async <T>(url: string, data?: any, config?: any): Promise<T> => {
const response = await baseAPI.put<CommonSuccessResponse<T>>(`/api/${v}${url}`, data, config);
return response.data.data;
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
delete: async <T>(url: string, config?: any): Promise<T> => {
const response = await baseAPI.delete<CommonSuccessResponse<T>>(`/api/${v}${url}`, config);
return response.data.data;
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
patch: async <T>(url: string, data?: any, config?: any): Promise<T> => {
const response = await baseAPI.patch<CommonSuccessResponse<T>>(`/api/${v}${url}`, data, config);
return response.data.data;
},
});
export const api = apiHelper('v1'); // breaking change 방지용
export const apiV1 = apiHelper('v1');
export const apiV2 = apiHelper('v2');
|