Fetch обёртка с обработкой ошибок
Тонкая обёртка над нативным
fetch, которая бросает исключение при HTTP-статусах 4xx/5xx и разделяет сетевые и HTTP-ошибки.
Задача
fetch не бросает ошибку при 404 или 500 — response.ok просто равен false. Копировать эту проверку в каждый вызов неудобно; нужна единая утилита для всего приложения.
Решение
// utils/fetch.js
class HttpError extends Error {
constructor(response) {
super(`HTTP ${response.status}: ${response.statusText}`);
this.name = 'HttpError';
this.status = response.status;
this.response = response;
}
}
async function fetchJSON(url, options = {}) {
let response;
try {
response = await fetch(url, {
headers: { 'Content-Type': 'application/json', ...options.headers },
...options,
});
} catch (err) {
// Сетевая ошибка: нет интернета, CORS, DNS
throw new Error(`Сетевая ошибка: ${err.message}`);
}
if (!response.ok) {
throw new HttpError(response);
}
// 204 No Content — тела нет
if (response.status === 204) return null;
return response.json();
}
export { fetchJSON, HttpError };
Использование:
import { fetchJSON, HttpError } from './utils/fetch.js';
// GET
const users = await fetchJSON('/api/users');
// POST
const created = await fetchJSON('/api/users', {
method: 'POST',
body: JSON.stringify({ name: 'Alice' }),
});
// Обработка ошибок
try {
await fetchJSON('/api/protected');
} catch (err) {
if (err instanceof HttpError) {
if (err.status === 401) redirectToLogin;
if (err.status === 404) showNotFound;
} else {
showNetworkError(err.message);
}
}
Ключевые моменты
fetchне бросает ошибку при 4xx/5xx — всегда проверяйresponse.ok.- Разделяй сетевые ошибки (catch блок) и HTTP-ошибки (
response.ok === false). HttpErrorхранитstatusиresponse— можно дочитать тело с сообщением от API.204 No Contentтребует отдельной проверки перед вызовомresponse.json.
Варианты
- axios — делает то же из коробки плюс interceptors, timeout, отмена запросов.
- ky — fetch-обёртка с retry, hooks, timeout; ~3 KB.
- Для TypeScript — см. Рецепт -- API-клиент с TypeScript.