Back to JavaScript tutorials
Intermediate15 min read

Fetch & Web APIs

Make HTTP requests and use essential browser APIs for storage, timing, and network control in production apps.

The Fetch API

`fetch(url, options)` returns a Promise resolving to a Response object. Check `response.ok` (status 200–299) before parsing — fetch does not reject on HTTP error status codes, a common gotcha for newcomers.

Set headers, method, body, credentials, and signal (for abort) via the options object. Use `response.json()`, `.text()`, or `.blob()` to consume the body — each can only be called once per response.

  • Fetch rejects only on network failure
  • Check `response.ok` for HTTP errors
  • Body stream consumed once
const res = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Alice' }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const users = await res.json();

AbortController and Timeouts

Pass `signal: controller.signal` to fetch and call `controller.abort()` to cancel in-flight requests. React effects should abort fetches on unmount to prevent state updates on unmounted components.

Combine AbortController with `setTimeout` for request timeouts, or use AbortSignal.timeout(ms) in modern browsers and Node 18+ for cleaner syntax.

  • Abort on component unmount
  • AbortSignal.timeout for deadlines
  • Cancel stale requests on rapid input
const controller = new AbortController();
fetch(url, { signal: controller.signal });
// cleanup: controller.abort();

Local Storage and Session Storage

Web Storage APIs persist key-value string pairs. `localStorage` survives browser restarts; `sessionStorage` is scoped to the tab session. Storage is synchronous and limited (~5MB) — do not store large payloads or secrets.

JSON.stringify/parse wraps objects for storage. Handle quota exceeded errors and migrate schema versions when stored shape changes between app releases.

  • localStorage persists; sessionStorage is tab-scoped
  • Store strings only — JSON wrap objects
  • Never store tokens unencrypted if XSS is possible
localStorage.setItem('prefs', JSON.stringify({ theme: 'dark' }));
const prefs = JSON.parse(localStorage.getItem('prefs') ?? '{}');

URL, URLSearchParams, and Headers

The URL API parses and builds URLs reliably across environments. URLSearchParams handles query string encoding and iteration without manual string concatenation.

The Headers object normalizes header names to lowercase and supports append vs set semantics for multi-value headers. Use these built-ins instead of regex parsing in application code.

  • URL API for safe URL construction
  • URLSearchParams for query strings
  • Headers for normalized HTTP headers
const url = new URL('/search', 'https://example.com');
url.searchParams.set('q', 'javascript');

Integrating Fetch in Applications

Wrap fetch in a small API client that handles base URLs, auth headers, error normalization, and retry policy. Centralizing this logic prevents duplicated boilerplate across components and ensures consistent error handling.

For SSR frameworks, distinguish server-side fetch (may need absolute URLs and cookie forwarding) from client-side fetch. Consider TanStack Query or SWR for caching, deduplication, and stale-while-revalidate semantics on the client.

  • Central API client with auth and errors
  • Different fetch config for server vs client
  • Data libraries for cache and dedup

Get In Touch


Ready to discuss your next project? Drop me a message.