JS Web APIs — Fetch API & HTTP Communication
Master asynchronous network requests: the modern fetch() pipeline, HTTP verbs (GET, POST, PUT, DELETE), header manipulation, AbortSignal timeouts, and bulletproof error handling patterns.
The Modern fetch() Execution Pipeline
Unlike older networking APIs, fetch() operates via two sequential Promise resolutions: the first resolves when HTTP response headers arrive, and the second streams and parses the body.
1. Anatomy of fetch() & The res.ok Guard
The single most frequent beginner bug with fetch() is expecting a try...catch block to catch 404 Not Found or 500 Internal Server errors. The Promise returned by fetch() rejects only if the network request itself fails (DNS lookup failure, user is offline, or CORS violation).
The Industry-Standard Guard Pattern
async function fetchUserData(userId) {
try {
const res = await fetch(`https://api.example.com/users/${userId}`);
// ✅ CRITICAL GUARD: Check res.ok (true if HTTP status is 200-299)
if (!res.ok) {
throw new Error(`HTTP Error! Status: ${res.status} (${res.statusText})`);
}
const data = await res.json();
return data;
} catch (err) {
console.error('Fetch operation failed:', err.message);
throw err;
}
}
Run in Playground
2. RESTful HTTP Verbs: POST, PUT & DELETE in Action
By default, calling fetch(url) executes a GET request. Modifying data requires specifying the method, setting the Content-Type header, and stringifying the payload body.
const res = await fetch('/api/articles', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
body: JSON.stringify({
title: 'Mastering Fetch API',
category: 'javascript'
})
});
const newPost = await res.json();
const res = await fetch('/api/articles/94', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer ' + token
}
});
if (res.ok) {
console.log('Article deleted successfully');
}
Query Parameters with URLSearchParams
Avoid fragile manual string concatenations like url + '?a=' + a + '&b=' + b:
const params = new URLSearchParams({
search: 'javascript mastery',
limit: '20',
sort: 'desc'
});
const url = `https://api.example.com/posts?${params.toString()}`;
const res = await fetch(url);
Test in Playground
3. Modern Request Cancellation & Timeouts
By default, a browser fetch() request will hang indefinitely until the server closes the connection or browser socket times out. Modern JavaScript introduces two elegant solutions via AbortController and AbortSignal.timeout():
AbortSignal.timeout(ms) (Modern Standard)Automatically aborts if the server fails to reply within the specified millisecond threshold:
try {
const res = await fetch('/api/data', {
signal: AbortSignal.timeout(5000) // 5s timeout!
});
} catch (err) {
if (err.name === 'TimeoutError') {
console.error('Request timed out!');
}
}
new AbortController() (Manual Cancellation)Allows cancelling in-flight requests when a user types in a live search auto-complete box:
const controller = new AbortController();
fetch('/api/search', { signal: controller.signal });
// Cancel user search if they type new key:
cancelBtn.onclick = () => controller.abort();
Interactive Lab: HTTP Request Simulator
Live SandboxTest real HTTP communication against a live mock REST API (JSONPlaceholder). Select the HTTP method, inspect the response headers, and view serialized JSON output.
Build a Production-Grade API Client with Automatic Retries
Implement an apiFetch(url, options, maxRetries) wrapper. If the request encounters a network error or a 5xx server failure, it retries up to maxRetries with exponential backoff before throwing a descriptive error.
async function apiFetch(url, options = {}, retries = 3, backoff = 1000) {
try {
const res = await fetch(url, {
...options,
signal: options.signal || AbortSignal.timeout(8000)
});
if (!res.ok) {
// Retry on 5xx server errors
if (res.status >= 500 && retries > 0) {
console.warn(`Server error ${res.status}. Retrying in ${backoff}ms...`);
await new Promise(r => setTimeout(r, backoff));
return apiFetch(url, options, retries - 1, backoff * 2);
}
throw new Error(`HTTP Error ${res.status}: ${res.statusText}`);
}
return await res.json();
} catch (err) {
// Retry on network drops
if (retries > 0 && err.name !== 'AbortError') {
console.warn(`Network failure. Retrying in ${backoff}ms...`);
await new Promise(r => setTimeout(r, backoff));
return apiFetch(url, options, retries - 1, backoff * 2);
}
throw err;
}
}
Chapter 31 Knowledge Check
Validate your understanding of fetch promises, status guards, request options, and timeout cancellation.
fetch() reject?response.ok to be true?res.json()) be read multiple times?