97 lines
2.9 KiB
TypeScript
97 lines
2.9 KiB
TypeScript
// Утилиты для работы с API
|
||
|
||
const getApiUrl = (): string => {
|
||
if (typeof window === 'undefined') {
|
||
// SSR
|
||
return process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
||
}
|
||
|
||
const isLocalhost = window.location.hostname === 'localhost';
|
||
return isLocalhost
|
||
? 'http://localhost:3001'
|
||
: process.env.NEXT_PUBLIC_API_URL || 'https://your-api-domain.com';
|
||
};
|
||
|
||
export const apiUrl = getApiUrl();
|
||
|
||
export interface ApiResponse<T = unknown> {
|
||
success: boolean;
|
||
data?: T;
|
||
error?: string;
|
||
errors?: Array<{ msg?: string; param?: string }>; // Ошибки валидации
|
||
}
|
||
|
||
export async function apiRequest<T = unknown>(
|
||
endpoint: string,
|
||
options: RequestInit = {}
|
||
): Promise<ApiResponse<T>> {
|
||
try {
|
||
// Добавляем timeout через AbortController
|
||
const controller = new AbortController();
|
||
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 секунд
|
||
|
||
console.log(`[API] Request to: ${apiUrl}/api/${endpoint}`);
|
||
|
||
const response = await fetch(`${apiUrl}/api/${endpoint}`, {
|
||
...options,
|
||
signal: controller.signal,
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
...options.headers,
|
||
},
|
||
});
|
||
|
||
clearTimeout(timeoutId);
|
||
|
||
// Сначала читаем ответ как текст, потом парсим JSON
|
||
const responseText = await response.text();
|
||
let data: any;
|
||
|
||
if (responseText) {
|
||
try {
|
||
data = JSON.parse(responseText);
|
||
} catch (jsonErr) {
|
||
// Если не удалось распарсить JSON, возвращаем текст как ошибку
|
||
console.error('Failed to parse JSON response:', responseText);
|
||
return {
|
||
success: false,
|
||
error: `Invalid JSON response: ${responseText.substring(0, 100)}`,
|
||
};
|
||
}
|
||
} else {
|
||
data = {};
|
||
}
|
||
|
||
// Если статус не успешный, возвращаем данные с ошибкой
|
||
// (могут содержать детали валидации)
|
||
if (!response.ok) {
|
||
return {
|
||
success: false,
|
||
error: data.error || data.message || `HTTP error! status: ${response.status}`,
|
||
errors: data.errors, // Ошибки валидации, если есть
|
||
};
|
||
}
|
||
|
||
return data;
|
||
} catch (err) {
|
||
console.error('[API] Error:', err);
|
||
let errorMessage = 'Unknown error';
|
||
|
||
if (err instanceof Error) {
|
||
if (err.name === 'AbortError') {
|
||
errorMessage = 'Request timeout - сервер не отвечает';
|
||
} else if (err.message.includes('Failed to fetch')) {
|
||
errorMessage = 'Не удалось подключиться к серверу. Проверьте, что бэкенд запущен.';
|
||
} else {
|
||
errorMessage = err.message;
|
||
}
|
||
}
|
||
|
||
return {
|
||
success: false,
|
||
error: errorMessage,
|
||
};
|
||
}
|
||
}
|
||
|