JavaScript · API · Advanced
Error Handling
Handle HTTP errors and network failures robustly using response.ok and try/catch.
Quick topic start and explanations before exercises (exercises below):
Practical error handling patterns
#Error handling reference
#Exercises:
Check response.ok
#Fetch `/api/products/99999/` (non-existent). Print `response.status` and `response.ok`. Then fetch `/api/products/1/` and compare.
const BASE_URL = 'https://apilearn.tukas.dev';
async function main() {
// fetch missing product — print status and ok
// fetch real product — print status and ok
}
main();
Solution
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();
Throw on HTTP error
#Write a `getProduct(id)` function that fetches a product and throws an `Error` if `response.ok` is false. Call it with a valid id and with `99999`. Catch and print the error message.
const BASE_URL = 'https://apilearn.tukas.dev';
async function getProduct(id) {
// fetch, check response.ok, throw if not ok
}
async function main() {
// call with valid id
// call with 99999 and catch the error
}
main();
Solution
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();
Handle 401 Unauthorized
#Try to fetch `/api/users/profile/` without a token. Check `response.status` — if it's 401, print a specific message. Otherwise print the data.
const BASE_URL = 'https://apilearn.tukas.dev';
async function main() {
// fetch profile without auth, handle 401 specifically
}
main();
Solution
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 wrapper
#Write a `safeFetch(url)` function that checks `response.ok` and returns `null` (printing the error) on failure, or the parsed JSON on success. Test with a valid URL and a 404 URL.
const BASE_URL = 'https://apilearn.tukas.dev';
async function safeFetch(url) {
// fetch, check ok, return json or 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();
Solution
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();
Timeout with AbortController
#Write a `fetchWithTimeout(url, ms)` function that aborts the request if it takes longer than `ms` milliseconds. Test it with a normal request and print the result or `"timed out"`.
const BASE_URL = 'https://apilearn.tukas.dev';
async function fetchWithTimeout(url, ms = 3000) {
// use AbortController to abort after ms milliseconds
}
async function main() {
const data = await fetchWithTimeout(`${BASE_URL}/api/products/`, 5000);
console.log(data ? data.count : 'timed out');
}
main();
Solution
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();