Chapter 1 of ?
js 9 min read

JavaScript Mastery — Chapter 31: JS Web APIs — Fetch API & HTTP Communication

Module 7: Browser DOM & Web APIs • Chapter 31

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. fetch(url, options) RequestInit { method, headers, body, signal } Network 2. Response Object Status: res.status (200, 404) Validation: res.ok (true/false) Stream Body 3. Stream Deserializer await res.json() or .text() / .blob() ⚠️ CRITICAL PRODUCTION GOTCHA fetch() does NOT reject on HTTP 404 or 500 errors! It rejects ONLY on complete network failure (e.g. offline).

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.

POST: Creating a Resource
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();
DELETE: Removing a Resource
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 Sandbox

Test real HTTP communication against a live mock REST API (JSONPlaceholder). Select the HTTP method, inspect the response headers, and view serialized JSON output.

// Click "Send Request" to dispatch HTTP request...
Hands-on Challenge

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.

1. When does the Promise returned by fetch() reject?
Whenever the server returns HTTP 404 or 500
Only on complete network failure, DNS error, or CORS block
Whenever the response body is not valid JSON
Whenever response.ok is false
2. What HTTP status code range causes response.ok to be true?
Status code exactly 200
200 through 299 inclusive
100 through 399
Any status code other than 500
3. When sending a JSON payload via POST, which HTTP header must be included?
Accept-Encoding: gzip
'Content-Type': 'application/json'
'X-Requested-With': 'XMLHttpRequest'
'Cache-Control': 'no-cache'
4. What modern API allows cancelling or timing out a fetch() request after a given number of milliseconds?
fetch.cancel()
AbortSignal.timeout(ms) or AbortController
window.stop()
clearTimeout(fetch)
5. Can the response body stream (e.g. res.json()) be read multiple times?
Yes, unlimited times
No, the response body is a readable stream that can only be consumed once unless cloned via res.clone()
Yes, but only in Node.js
Only if credentials are included
Done with this chapter?
Mark it complete to track your progress and unlock your certificate.
Next Up
—

Learner Reviews

Write a Review
Share your experience to help other learners.
Your Rating *
★ ★ ★ ★ ★