dressed_for_succes_store/frontend/lib/api.ts

240 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import axios from 'axios';
// Получаем URL API из переменных окружения или используем значение по умолчанию
export const PUBLIC_API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api';
export const PUBLIC_BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:8000';
// Константа для ключа токена в localStorage
const TOKEN_KEY = 'token';
// Отладочный режим для API
export const apiStatus = {
debugMode: true, // Временно включаем отладочный режим для диагностики проблем
// debugMode: process.env.NEXT_PUBLIC_DEBUG === 'true',
connectionError: false,
lastConnectionError: null as Error | null,
isAuthenticated: false, // Флаг аутентификации пользователя
// Метод для проверки статуса соединения с API
checkConnection: async (): Promise<boolean> => {
try {
const response = await fetch(`${PUBLIC_API_URL}/health`, {
method: 'GET',
cache: 'no-store',
});
apiStatus.connectionError = !response.ok;
return response.ok;
} catch (error) {
apiStatus.connectionError = true;
apiStatus.lastConnectionError = error as Error;
return false;
}
}
};
// Для отладки выводим URL API в консоль
if (apiStatus.debugMode) {
console.log('API URL:', PUBLIC_API_URL);
console.log('BASE URL:', PUBLIC_BASE_URL);
}
// Получение токена из localStorage
const getToken = (): string | null => {
try {
return localStorage.getItem(TOKEN_KEY);
} catch (error) {
console.error('Ошибка при получении токена (api.ts):', error);
return null;
}
};
// Создаем экземпляр клиента Axios с базовыми настройками
const instance = axios.create({
baseURL: PUBLIC_API_URL,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
timeout: 30000, // 30 секунд таймаут для запросов
});
// Добавляем перехватчик для исходящих запросов
instance.interceptors.request.use(
(config) => {
// Получаем токен из localStorage (если он есть)
const token = typeof window !== 'undefined' ? getToken() : null;
// Если токен есть, добавляем его в заголовки запроса
if (token) {
config.headers = config.headers || {};
config.headers.Authorization = `Bearer ${token}`;
apiStatus.isAuthenticated = true;
} else {
apiStatus.isAuthenticated = false;
}
// Логируем URL запроса в режиме отладки
if (apiStatus.debugMode) {
console.log(`API Request: ${config.method?.toUpperCase()} ${config.url}`);
}
return config;
},
(error) => {
// Обработка ошибок при подготовке запроса
console.error('API Request Error:', error);
return Promise.reject(error);
}
);
// Добавляем перехватчик для входящих ответов
instance.interceptors.response.use(
function(response: any) {
// Обработка успешного ответа
if (apiStatus.debugMode) {
console.log(`API Response ${response.status} for ${response.config.url}`);
}
return response.data;
},
function(error: any) {
// Проверяем, является ли ошибка 401 (неавторизован) для запроса корзины
// и пользователь не аутентифицирован - это ожидаемое поведение
if (error.response && error.response.status === 401) {
// Для запросов к корзине, когда пользователь не аутентифицирован,
// просто возвращаем пустой объект без логирования ошибки
if (!apiStatus.isAuthenticated &&
error.config.url &&
(error.config.url.includes('/cart') || error.config.url.includes('/wishlist'))) {
return Promise.resolve({});
}
// Логируем 401 ошибку, но НЕ удаляем токен, чтобы избежать проблем при перезагрузке
console.log('Получен 401 ответ от API. Возможно, токен истек или недействителен.');
// Больше не перенаправляем на страницу входа автоматически
// это должно делаться на уровне компонентов проверки авторизации
}
// Логируем ошибки в режиме отладки
if (apiStatus.debugMode) {
if (error.response) {
console.error(`API Error ${error.response.status}: ${error.response.statusText}`);
console.error('API Error Response Data:', error.response.data);
} else if (error.request) {
console.error('API No Response Received:', error.request);
} else {
console.error('API Request Setup Error:', error.message);
}
}
return Promise.reject(error);
}
);
// Общий интерфейс для ответа API
export interface ApiResponse<T = any> {
success: boolean;
data?: T;
message?: string;
error?: string;
}
// API клиент
const api = {
// GET запрос
get: async <T>(url: string, params = {}): Promise<T> => {
try {
return await instance.get(url, { params }) as unknown as T;
} catch (error) {
if (apiStatus.debugMode) {
console.error(`GET Error for ${url}:`, error);
}
throw error;
}
},
// POST запрос
post: async <T>(url: string, data = {}, config = {}): Promise<T> => {
try {
return await instance.post(url, data, config) as unknown as T;
} catch (error) {
if (apiStatus.debugMode) {
console.error(`POST Error for ${url}:`, error);
}
throw error;
}
},
// PUT запрос
put: async <T>(url: string, data = {}, config = {}): Promise<T> => {
try {
return await instance.put(url, data, config) as unknown as T;
} catch (error) {
if (apiStatus.debugMode) {
console.error(`PUT Error for ${url}:`, error);
}
throw error;
}
},
// DELETE запрос
delete: async <T>(url: string, config = {}): Promise<T> => {
try {
return await instance.delete(url, config) as unknown as T;
} catch (error) {
if (apiStatus.debugMode) {
console.error(`DELETE Error for ${url}:`, error);
}
throw error;
}
},
};
// Функция для выполнения запросов к API с унифицированным обработчиком ошибок
export async function fetchApi<T>(
url: string,
options: RequestInit = {}
): Promise<ApiResponse<T>> {
try {
const token = typeof window !== 'undefined' ? getToken() : null;
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'Accept': 'application/json',
...(options.headers as Record<string, string> || {})
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch(`${PUBLIC_API_URL}${url}`, {
...options,
headers,
});
const data = await response.json();
if (!response.ok) {
return {
success: false,
error: data.detail || 'Ошибка при запросе к API',
message: data.message || 'Произошла ошибка при выполнении запроса',
};
}
return {
success: true,
data: data as T,
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Неизвестная ошибка',
message: 'Произошла ошибка при выполнении запроса',
};
}
}
export default api;