Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Working with APIs  ›  Lesson

The Fetch API

Fetch 10 minfetch(url) sends a request and immediately returns a Promise for the response's headers; a second await on response.json() (or .text()) gets the body. fetch only rejects on a genuine network failure — a 404 or 500 still resolves normally, so response.ok must be checked by hand.

The Fetch API

In short: fetch(url) sends a postcard and hands you a Promise immediately — before any response has arrived. awaiting it gives you a Response once the headers arrive; the body isn't parsed yet. A second await, on response.json() (or .text(), .blob()), actually reads and parses the body. The trap: fetch's Promise only rejects on a genuine network failure — a 404 or 500 still counts as a successful fetch, so response.ok has to be checked by hand. This lesson's code talks to a real network, which this sandbox can't do — read it, don't run it.

fetch(url) returns a Promise right away; await response gives the headers; await response.json() gives the parsed body — two awaits, not one; a trap note that fetch only rejects on a network failure, a 404 or 500 still resolves, so check response.ok yourself

Fetching a playlist

The everyday shape: two awaits, one for the response, one for the body.

async function loadPlaylist() {
  const response = await fetch("/api/playlist");
  const songs = await response.json();
  console.log(songs.length, "songs loaded");
  return songs;
}

The first await resolves once the server has replied with headers and a status code — response at that point knows the status, but hasn't read the body yet. The second await, on response.json(), does the actual reading and JSON-parsing, and is itself asynchronous because the body can arrive in pieces over the network.

Checking for a failed request

Because fetch doesn't reject on HTTP error statuses, checking response.ok is a habit worth having on every fetch:

async function loadSong(id) {
  const response = await fetch(`/api/songs/${id}`);
  if (!response.ok) {
    throw new Error(`request failed: ${response.status}`);
  }
  return response.json();
}

try {
  const song = await loadSong(999); // doesn't exist — server replies 404
  console.log(song);
} catch (err) {
  console.log("caught:", err.message);
}

response.ok is true only for status codes 200–299. A 404 here still resolves the fetch Promise successfully — the request genuinely completed, the server just said "not found." The if (!response.ok) check is what turns that into a throw, which the surrounding try/catch can then handle the normal way.

Sending data, not just requesting it

A second argument configures the request — method, headers, and a body for anything other than a plain GET:

async function addSong(song) {
  const response = await fetch("/api/songs", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(song),
  });
  if (!response.ok) {
    throw new Error(`could not add song: ${response.status}`);
  }
  return response.json();
}

JSON.stringify(song) turns the JavaScript object into the text the server expects, and the Content-Type header tells the server how to interpret it. The same response.ok check applies here — a failed POST resolves just like a failed GET does.

🎯 Your turn

A developer writes const response = await fetch("/api/user/999"); const user = await response.json(); and expects a catch block around it to run when the server replies 404 for a user that doesn't exist — but it never does. Explain why, and show how to fix the code so the failure is actually caught.

Quick practice

quick drill

What does await fetch(url) give you, the moment it resolves?

quick drill

Does fetch("/api/songs/999") reject when the server replies with a 404?

quick drill

What does response.ok tell you?

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainA 404 that doesn't reject

A developer writes const response = await fetch("/api/user/999"); const user = await response.json(); and expects a catch block to run when the user doesn't exist (server replies 404), but it never does. Explain why, and how to fix the code.