Script Valley
JavaScript: The Complete Language
Asynchronous JavaScriptLesson 4.5

Fetching data from APIs with fetch and handling errors

fetch API, Request Response objects, response.json, HTTP status codes, network errors vs HTTP errors, AbortController, headers, POST request, error handling pattern

fetch — The Browser's Built-In HTTP Client

fetch returns a Promise that resolves when the server responds — including for 4xx and 5xx status codes. A network failure (no connection, DNS error) rejects the Promise. An HTTP error status does not reject it. You must check both explicitly. This distinction is the single most common source of silent fetch bugs in production applications.

GET Request Pattern

async function getUser(id) {
  const res = await fetch(`https://api.example.com/users/${id}`);

  // fetch resolves for 404, 500, etc. — must check manually
  if (!res.ok) {
    throw new Error(`HTTP ${res.status}: ${res.statusText}`);
  }

  return res.json(); // also returns a Promise
}

POST Request

async function createUser(data) {
  const res = await fetch("https://api.example.com/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data)
  });

  if (!res.ok) throw new Error(`Failed: ${res.status}`);
  return res.json();
}

Cancellation with AbortController

const controller = new AbortController();

fetch(url, { signal: controller.signal })
  .catch(err => {
    if (err.name === "AbortError") console.log("Request cancelled");
    else throw err;
  });

// Cancel if no response within 3 seconds
setTimeout(() => controller.abort(), 3000);

Critical Pattern

Always check res.ok before calling res.json(). A 404 response body is perfectly valid JSON describing an error payload — without the check, you parse failure as success and wonder why the data looks wrong.