← thecodex.expert · The Codex Family of Knowledge
The Codex / JavaScript / Fetch API

Fetch API

Making HTTP requests from JavaScript — fetch(), Request, Response, Headers, streaming, and abort.

What it is, in plain English: The Fetch API is the modern way to make HTTP requests from JavaScript. fetch(url) returns a Promise that resolves to a Response object. You then call response.json(), response.text(), or response.blob() to read the body — these also return Promises. Fetch is available in all modern browsers and in Node.js from v18.
Where this bites you

A streamed response arrives in chunks, and chunk boundaries have nothing to do with your lines. The network can split a message anywhere, even in the middle of a JSON string. Code that splits each chunk on "\n" and parses every line works on localhost, where chunks are tidy, and then crashes in production with SyntaxError: Unterminated string in JSON.

async function readTokens() {
  const res    = await fetch("/api/ai/stream");
  const reader = res.body.getReader();
  const dec    = new TextDecoder();
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    const lines = dec.decode(value).split("\n");   // assumes each chunk holds whole lines
    for (const line of lines) {
      if (line.startsWith("data: ")) {
        console.log(JSON.parse(line.slice(6)).token);
      }
    }
  }
}
readTokens().catch(e => console.log(`${e.name}: ${e.message}`));
// server sends 'data: {"token":"Hel"}\ndata: {"tok' and then 'en":"lo"}\n'
// Hel
// SyntaxError: Unterminated string in JSON at position 5 (line 1 column 6)

Making HTTP requests from the browser

Before fetch(), you needed XMLHttpRequest — verbose, callback-based, and painful. fetch() is clean, Promise-based, and works everywhere.

The simplest GET request

// fetch() returns a Promise → use await inside an async function
async function getUser() {
  const response = await fetch("https://api.example.com/user/1");

  // IMPORTANT: fetch() only rejects on network failure, not HTTP errors.
  // A 404 or 500 still "succeeds" — you must check response.ok:
  if (!response.ok) {
    throw new Error(`Failed: ${response.status}`);
  }

  const user = await response.json();  // parse the JSON body
  console.log(user.name);
}

getUser();

POST, PUT, DELETE — sending data

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

// PUT — update a resource:
await fetch(`/api/users/${id}`, {
  method:  "PUT",
  headers: { "Content-Type": "application/json" },
  body:    JSON.stringify({ name: "Updated Name" }),
});

// DELETE:
await fetch(`/api/users/${id}`, { method: "DELETE" });

// With authentication header:
await fetch("/api/protected", {
  headers: {
    "Authorization": `Bearer ${token}`,
    "Content-Type": "application/json",
  },
});

Handling errors properly

async function apiFetch(url, options = {}) {
  try {
    const response = await fetch(url, options);

    if (!response.ok) {
      // Try to get error details from the response body:
      const error = await response.json().catch(() => ({}));
      throw new Error(error.message ?? `HTTP ${response.status}`);
    }

    return response.json();
  } catch (e) {
    if (e.name === "TypeError") {
      // Network error (offline, DNS failure, CORS blocked):
      throw new Error("Network error — check your connection");
    }
    throw e;
  }
}

// Usage:
try {
  const user = await apiFetch("/api/user/1");
  console.log(user.name);
} catch (e) {
  console.error(e.message);
}

Uploading files

// Use FormData — don't set Content-Type (browser sets it with boundary):
const form = document.querySelector("form");
const data = new FormData(form);

// Or build FormData manually:
const fd = new FormData();
fd.append("file", fileInput.files[0]);
fd.append("userId", "42");

const response = await fetch("/api/upload", {
  method: "POST",
  body:   fd,   // ← no Content-Type header! browser handles it
});
Try It Yourself

Official Sources

The Codex links only to official documentation and the ECMAScript specification. No third-party tutorials.