</> HTML5Advent
ENFRESDEITPT

// apis · Web Platform Advent #1

The Fetch API in JavaScript: a practical guide

How to make HTTP requests in the browser with the Fetch API — GET, JSON, POST, error handling, and aborting requests — with runnable examples.

A code editor on screen showing HTML, CSS and JavaScript source

The Fetch API is the modern, promise-based way to make HTTP requests from the browser. It replaces the older XMLHttpRequest with a cleaner interface that works naturally with async/await and streams. Every current browser supports it.

A first GET request

fetch() returns a promise that resolves to a Response object. To read JSON from it, call response.json(), which itself returns a promise:

const res = await fetch('https://api.example.com/articles');
const data = await res.json();
console.log(data);

The same thing without async/await, using .then() chains:

fetch('https://api.example.com/articles')
  .then((res) => res.json())
  .then((data) => console.log(data));

The gotcha: fetch does not reject on HTTP errors

This trips up almost everyone. A 404 or 500 response is still a successful fetch — the promise only rejects on a network failure (offline, DNS, CORS). You must check response.ok yourself:

const res = await fetch(url);
if (!res.ok) {
  throw new Error(`HTTP ${res.status} ${res.statusText}`);
}
const data = await res.json();
A network switch with cables, representing data travelling between client and server
Every fetch() call sends an HTTP request across the network to a server and waits for the response to travel back.

Sending data with POST

Pass a second options argument to set the method, headers and body. For JSON, stringify the payload and set the Content-Type:

const res = await fetch('/api/articles', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ title: 'Hello', body: 'World' }),
});
const created = await res.json();

Aborting a request

Use an AbortController to cancel a request — useful for timeouts or when a component unmounts:

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);

try {
  const res = await fetch(url, { signal: controller.signal });
  const data = await res.json();
} catch (err) {
  if (err.name === 'AbortError') console.log('Request timed out');
} finally {
  clearTimeout(timeout);
}

Quick reference

TaskHow
Read JSONawait res.json()
Read textawait res.text()
Check successres.ok / res.status
Send JSONbody: JSON.stringify(...) + Content-Type
CancelAbortController + signal

That covers the everyday cases. The Fetch API also supports streaming response bodies, FormData uploads, and request/response cloning — but the patterns above handle the vast majority of real-world calls.