105 lines
3.0 KiB
TypeScript
105 lines
3.0 KiB
TypeScript
import axios, {
|
|
type AxiosInstance,
|
|
type AxiosResponse,
|
|
type AxiosError,
|
|
type InternalAxiosRequestConfig,
|
|
} from "axios";
|
|
|
|
export interface ApiResponse<T = any> {
|
|
data: T;
|
|
message?: string;
|
|
status: number;
|
|
}
|
|
|
|
class ApiClient {
|
|
private axiosInstance: AxiosInstance;
|
|
|
|
constructor() {
|
|
this.axiosInstance = axios.create({
|
|
baseURL: "http://213.165.213.170:8080/api/v1",
|
|
timeout: 10000,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
validateStatus: (status) => {
|
|
return status >= 200 && status < 400;
|
|
},
|
|
// Добавляем кастомный сериализатор параметров
|
|
paramsSerializer: {
|
|
serialize: (params) => {
|
|
const parts: string[] = [];
|
|
|
|
Object.entries(params).forEach(([key, value]) => {
|
|
if (value === undefined || value === null) return;
|
|
|
|
if (Array.isArray(value)) {
|
|
// Преобразуем массив в множественные параметры: level=info&level=warning
|
|
value.forEach((item) => {
|
|
if (item !== undefined && item !== null) {
|
|
parts.push(
|
|
`${encodeURIComponent(key)}=${encodeURIComponent(item)}`,
|
|
);
|
|
}
|
|
});
|
|
} else {
|
|
parts.push(
|
|
`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,
|
|
);
|
|
}
|
|
});
|
|
|
|
return parts.join("&");
|
|
},
|
|
},
|
|
});
|
|
|
|
this.setupInterceptors();
|
|
}
|
|
|
|
private setupInterceptors(): void {
|
|
this.axiosInstance.interceptors.request.use(
|
|
(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig => {
|
|
// Получаем токен из localStorage
|
|
const authStorage = localStorage.getItem("auth-storage");
|
|
if (authStorage) {
|
|
try {
|
|
const parsed = JSON.parse(authStorage);
|
|
const token = parsed.state?.token;
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
} catch (e) {
|
|
console.error("[Auth] Failed to parse auth storage:", e);
|
|
}
|
|
}
|
|
return config;
|
|
},
|
|
(error: AxiosError): Promise<AxiosError> => {
|
|
console.error("[Request Error]", error);
|
|
return Promise.reject(error);
|
|
},
|
|
);
|
|
|
|
this.axiosInstance.interceptors.response.use(
|
|
(response: AxiosResponse): AxiosResponse => {
|
|
console.log(`[Response] ${response.status} ${response.config.url}`);
|
|
return response;
|
|
},
|
|
async (error: AxiosError): Promise<any> => {
|
|
if (error.response?.status === 401) {
|
|
window.location.href = "/auth";
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
return Promise.reject(error);
|
|
},
|
|
);
|
|
}
|
|
|
|
public getInstance(): AxiosInstance {
|
|
return this.axiosInstance;
|
|
}
|
|
}
|
|
|
|
export const apiClient = new ApiClient().getInstance();
|