import { delay } from "@core/utils"; import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; import { getAppData, setAppData } from "../@core/utils/store"; import { ApiErrorCode } from "../@types"; import { useUserStore } from "../stores"; import { ApiError } from "./ApiError"; export const API_URL = (() => { if (sessionStorage.getItem("isApiTest") === "T") { return import.meta.env.VITE_TEST_API_URL; // 백엔드 개발자용 } return import.meta.env.VITE_API_URL ?? ""; })(); // console.table({ ...import.meta.env, API_URL, }); const _axios = axios.create({ baseURL: API_URL ?? "", }); const prepareRequest = async (config: AxiosRequestConfig) => { config.headers ??= { "Content-Type": "application/json; charset=utf-8", Accept: "application/json", }; }; export interface ApiRequestConfig extends AxiosRequestConfig { tryTime?: number; ignoreError?: boolean; } export type ApiMethod = "get" | "delete" | "head" | "post" | "put" | "patch" | "request"; export const apiWrapper = async

( method: ApiMethod, route: string, body?: any, config: ApiRequestConfig = {}, ): Promise> => { await prepareRequest(config); // remove undefined | null for (const key in body) { if (body[key] === undefined) { delete body[key]; } } const axiosConfig: AxiosRequestConfig = { ...config, }; switch (method) { case "request": { axiosConfig.method = body.method; break; } case "get": case "delete": case "head": { if (body?.pageNumber !== undefined) { body.pageNumber = Math.max(body.pageNumber - 1, 0); } const searchParams = new URLSearchParams(body).toString(); axiosConfig.method = method; axiosConfig.url = route + `${searchParams ? "?" + searchParams : ""}`; break; } case "post": case "put": case "patch": { axiosConfig.method = method; axiosConfig.url = route; axiosConfig.data = body; break; } default: break; } if (!axiosConfig.method) { throw { code: "ERR" }; } const { data, ...rest } = await _axios(axiosConfig); if (!config.ignoreError && data.error && data.error.code) { const tryTime = config.tryTime ?? 0; if (data.error.code === ApiErrorCode.EXPIRED_TOKEN && tryTime < 1) { const appData = getAppData(); if (appData) { const { data: _data, headers } = await _axios.post( import.meta.env.VITE_TOKEN_REFRESH_ROUTER ?? "/token/refresh", { token: appData.refreshToken, }, { headers: { Authorization: null, }, }, ); if (_data.error && _data.error.code) { await delay(10); if (_data.error.code === ApiErrorCode.INVALID_TOKEN) { await useUserStore.getState().signOut(); } if (_data.error.code === ApiErrorCode.INVALID_REFRESH_TOKEN) { await useUserStore.getState().signOut(); } config.tryTime = tryTime + 1; throw new ApiError(_data.error.code, _data.error.message, _data.error.data); } if (headers && headers.authorization) { setApiHeader(headers.authorization); // debugger; console.log("appData", appData); setAppData({ ...appData, authorization: headers.authorization, refreshToken: headers["refresh-token"] ?? "", }); } return await apiWrapper(method, route, body, config); } } throw new ApiError(data.error.code, data.error.message, data.error.data); } if (data && "page" in data) { data.page.pageNumber = Math.min(data.page.pageNumber + 1, data.page.pageCount); } return { data: data as P, ...rest }; }; export const setApiHeader = (token: string) => { _axios.defaults.headers.common["Authorization"] = token; };