Engrain by ByteRush

WEB.17.01 Mid-level· 11 minCore — asked often

Request, Response, headers and bodies: fetch beyond the basics

The Request and Response objects behind fetch, why a body can be read only once (bodyUsed, clone), the credentials, mode, cache, redirect, keepalive and priority options, and a fetch wrapper with proper errors.

Comes up in: Web fundamentals, Coding

Learn#

Asha’s error logger does await res.json() to show the error, then her retry code calls res.text() on the same response and crashes with “body already used”. The bug report hides the real error.

A call to fetch gives you a response object as soon as the headers arrive. Its body is a stream. You read it with json(), text() or blob(), and a stream can be read once:

const res = new Response(JSON.stringify({ ok: true }), { status: 201, headers: { "Content-Type": "application/json" } });
const copy = res.clone();
console.log(res.status, res.ok, res.headers.get("content-type"));
console.log(await res.json(), res.bodyUsed);
try { await res.text(); } catch (e) { console.log(e.name); }
console.log(await copy.text());
const req = new Request("https://api.example/orders", { method: "POST", body: "{}" });
console.log(req.method, req.credentials, req.mode);

Output (verified)

201 true application/json
{ ok: true } true
TypeError
{"ok":true}
POST same-origin cors

A request object holds the URL, method, headers, body and options; fetch(request) sends it. clone() lets two readers share one body.

One body, one readStep 1 of 4

Network

  • headers ✓ 201
  • body: streaming …

State

    empty

    Console

      empty

      fetch resolves as soon as the headers arrive. The body is still a stream coming over the network.

      Read the steps as text
      1. fetch resolves as soon as the headers arrive. The body is still a stream coming over the network.
      2. res.json() reads the stream to the end and parses it. bodyUsed becomes true.
      3. Calling res.text() now throws a TypeError: the stream was already consumed.
      4. res.clone(), made before the first read, splits the stream in two, so each copy can be read once.

      Predict#

      Predict first

      fetch('/api/missing') gets a 404. What does the fetch promise do?

      Interview angle#

      Say it like this — about 30 seconds

      “The fetch call resolves with a Response once the headers arrive. The body is a stream that can be read only once. After that, bodyUsed is true, so I call clone first if two readers need it. The fetch call rejects only on network errors, so I always check res.ok. For cookies on a cross-origin request I set credentials to include. The server must then allow credentials for my exact origin. Other options control mode, cache, redirects, keepalive and priority.”

      Stays on your device. Nothing is uploaded.
      Follow-up Why can you read a response body only once?
      The body is a stream; reading consumes it. Use res.clone() before reading if you need it twice.
      Follow-up How do you send cookies with a cross-origin fetch?
      credentials: "include", and the server must reply with the exact origin and Access-Control-Allow-Credentials: true; SameSite must also allow it.
      Follow-up When do you use keepalive?
      For small requests that must finish after the page unloads, such as analytics; the body limit is 64 KB in total.

      Practice#

      Guided

      Write a fetchJson wrapper that checks the status, reads the body once, and returns useful errors.

      Done when

      • An Accept: application/json header is added, keeping the caller’s headers.
      • 204 resolves null; other ok responses resolve the parsed body.
      • Errors carry status and the parsed JSON body or the text.
      Your solution
      Ctrl/⌘ + Enter

      Remember#

      Try to answer each card before you open it. Then add them to your reviews.

      Does fetch reject on a 404?

      No. It resolves; check res.ok or res.status.

      How do you read a response body twice?

      Call res.clone() before the first read.

      What is fetch's default credentials mode?

      same-origin.

      What does keepalive: true do?

      Lets a small request finish after the page unloads.

      Go deeper

      Four layers. Stop at the one your interview needs; each ends with a quick check.

      The core ideaEvery round
      Credentials are cookies and HTTP auth: omit, same-origin (default) or include.
      mode is cors (default), same-origin (fail on cross-origin) or no-cors (an opaque response you cannot read).
      Check yourself: What does mode: 'no-cors' give you?

      An opaque response you cannot read; only useful for caching or fire-and-forget.

      How it works underneathSenior rounds
      The cache option controls the HTTP cache for one request. Use no-store to skip it, no-cache to revalidate, or force-cache to prefer a cached copy.
      redirect is follow (default), error or manual.
      Check yourself: What does cache: 'no-store' do on a fetch?

      Skips the HTTP cache completely for that request.

      Edge cases and trapsWhere people slip

      keepalive: true lets a request outlive the page, like sendBeacon, but in-flight keepalive bodies are limited to 64 KB in total Source: Fetch Standard: keepalive.
      A JSON error body may actually be HTML from a proxy; check content-type before parsing.

      Check yourself: What is the size limit for keepalive requests?

      64 KB in total across in-flight keepalive requests.

      In productionStaff-level answers

      priority: "high" or "low" hints how important a request is, such as low for prefetching Source: MDN: RequestInit.
      Wrap fetch once per app: base URL, auth, JSON, timeouts (JS.11.06) and typed errors.

      Check yourself: Which fetch option lowers the priority of a background request?

      priority: 'low'.

      Finished the five steps? Mark it, and its cards join your reviews.

      Last checked 2026-11-01. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

      Interview questions this answers

      • Why can you read a response body only once?
      • How do you send cookies with a cross-origin fetch?