JavaScript · API · Просунутий
Обробка помилок
Надійно обробляйте HTTP-помилки та збої мережі за допомогою response.ok і try/catch.
Короткий вступ до теми та пояснення перед вправами (вправи нижче):
Практичні паттерни обробки помилок
#Довідник обробки помилок
#Вправи:
Перевірити response.ok
#Виконайте запит до `/api/products/99999/` (неіснуючий). Виведіть `response.status` і `response.ok`. Потім виконайте запит до `/api/products/1/` і порівняйте.
const BASE_URL = 'https://apilearn.tukas.dev';
async function main() {
// запит до неіснуючого товару — вивести status і ok
// запит до реального товару — вивести status і ok
}
main();
Рішення
const BASE_URL = 'https://apilearn.tukas.dev';
async function main() {
const r1 = await fetch(`${BASE_URL}/api/products/99999/`);
console.log(r1.status, r1.ok); // 404 false
const r2 = await fetch(`${BASE_URL}/api/products/1/`);
console.log(r2.status, r2.ok); // 200 true
}
main();
Кинути виняток при HTTP-помилці
#Напишіть функцію `getProduct(id)`, яка отримує товар і кидає `Error`, якщо `response.ok` дорівнює `false`. Викличте її з дійсним id та з `99999`. Перехопіть і виведіть повідомлення про помилку.
const BASE_URL = 'https://apilearn.tukas.dev';
async function getProduct(id) {
// fetch, перевірити response.ok, кинути виняток якщо не ok
}
async function main() {
// викликати з дійсним id
// викликати з 99999 і перехопити помилку
}
main();
Рішення
const BASE_URL = 'https://apilearn.tukas.dev';
async function getProduct(id) {
const response = await fetch(`${BASE_URL}/api/products/${id}/`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
async function main() {
try {
const p = await getProduct(1);
console.log(p.name);
} catch (err) {
console.log('Error:', err.message);
}
try {
await getProduct(99999);
} catch (err) {
console.log('Error:', err.message); // HTTP 404
}
}
main();
Обробити 401 Unauthorized
#Спробуйте запитати `/api/users/profile/` без токена. Перевірте `response.status` — якщо це 401, виведіть конкретне повідомлення. Інакше виведіть дані.
const BASE_URL = 'https://apilearn.tukas.dev';
async function main() {
// запит профілю без авторизації, окрема обробка 401
}
main();
Рішення
const BASE_URL = 'https://apilearn.tukas.dev';
async function main() {
const response = await fetch(`${BASE_URL}/api/users/profile/`);
if (response.status === 401) {
console.log('Unauthorized — provide a valid token');
} else if (!response.ok) {
console.log(`HTTP error: ${response.status}`);
} else {
const data = await response.json();
console.log(data.username);
}
}
main();
Обгортка safeFetch
#Напишіть функцію `safeFetch(url)`, яка перевіряє `response.ok` і повертає `null` (виводячи помилку) при збої, або розібраний JSON при успіху. Перевірте з дійсним URL та URL що повертає 404.
const BASE_URL = 'https://apilearn.tukas.dev';
async function safeFetch(url) {
// fetch, перевірити ok, повернути json або null
}
async function main() {
const good = await safeFetch(`${BASE_URL}/api/products/1/`);
console.log(good ? good.name : 'null');
const bad = await safeFetch(`${BASE_URL}/api/products/99999/`);
console.log(bad);
}
main();
Рішення
const BASE_URL = 'https://apilearn.tukas.dev';
async function safeFetch(url) {
try {
const response = await fetch(url);
if (!response.ok) {
console.error(`HTTP ${response.status} for ${url}`);
return null;
}
return response.json();
} catch (err) {
console.error('Network error:', err.message);
return null;
}
}
async function main() {
const good = await safeFetch(`${BASE_URL}/api/products/1/`);
console.log(good ? good.name : 'null');
const bad = await safeFetch(`${BASE_URL}/api/products/99999/`);
console.log(bad);
}
main();
Таймаут через AbortController
#Напишіть функцію `fetchWithTimeout(url, ms)`, яка перериває запит, якщо він виконується довше ніж `ms` мілісекунд. Перевірте на звичайному запиті та виведіть результат або `"timed out"`.
const BASE_URL = 'https://apilearn.tukas.dev';
async function fetchWithTimeout(url, ms = 3000) {
// використати AbortController для переривання через ms мілісекунд
}
async function main() {
const data = await fetchWithTimeout(`${BASE_URL}/api/products/`, 5000);
console.log(data ? data.count : 'timed out');
}
main();
Рішення
const BASE_URL = 'https://apilearn.tukas.dev';
async function fetchWithTimeout(url, ms = 3000) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), ms);
try {
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timer);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
} catch (err) {
if (err.name === 'AbortError') {
console.log('Request timed out');
return null;
}
throw err;
}
}
async function main() {
const data = await fetchWithTimeout(`${BASE_URL}/api/products/`, 5000);
console.log(data ? data.count : 'timed out');
}
main();