Technology · JavaScript

JavaScript Fetch API

Master the Fetch API for making HTTP requests in JavaScript, including GET, POST, error handling, and working with JSON responses.

  • JavaScript Fetch API
  • JavaScript Fetch API Guide
  • JavaScript Fetch API Tips
  • JavaScript Fetch API Tutorial
  • JavaScript Fetch API Reference
TL;DR
  1. 01Use fetch() to make HTTP requests and always await the response before parsing it.
  2. 02Check response.ok before parsing — fetch only rejects on network failure, not HTTP errors.
  3. 03Use async/await with try/catch for clean, readable fetch code.

Basic GET Request

The Fetch API is the modern, promise-based way to make HTTP requests in JavaScript. It replaces older approaches like XMLHttpRequest.

async function getUser(id) {
  const response = await fetch(`/api/users/${id}`);
  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`);
  }
  return response.json();
}
  • fetch(url) returns a Promise that resolves to a Response object.
  • response.ok is true for status codes 200–299. Always check it.
  • response.json() parses the body as JSON and returns another Promise.
  • Fetch only rejects on network-level failures (no connection, DNS failure). A 404 or 500 does not reject — you must check response.ok yourself.

POST Request with JSON Body

Sending data requires setting the method, headers, and body in the options object.

async function createPost(data) {
  const response = await fetch('/api/posts', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  });
  if (!response.ok) throw new Error('Request failed');
  return response.json();
}
Option Purpose Example
method HTTP verb 'POST', 'PUT', 'DELETE'
headers Request headers { 'Content-Type': 'application/json' }
body Request payload JSON.stringify(data)
credentials Send cookies 'include' or 'same-origin'

Error Handling Patterns

Robust fetch code handles both network errors and HTTP error responses.

async function safeFetch(url, options = {}) {
  try {
    const res = await fetch(url, options);
    if (!res.ok) {
      const msg = await res.text();
      throw new Error(`${res.status}: ${msg}`);
    }
    return await res.json();
  } catch (err) {
    console.error('Fetch failed:', err);
    throw err;
  }
}
  • Wrap fetch in try/catch to catch network-level errors (offline, CORS, DNS).
  • Check response.ok inside the try block to catch HTTP errors (4xx, 5xx).
  • Read res.text() or res.json() on error responses to get the server's error message.

Warning: Calling response.json() on an error response that returns HTML (like a 404 page) will throw a JSON parse error. Use res.text() as a safe fallback when the content type is unknown.

Common Fetch Patterns

These patterns cover the most frequent real-world fetch use cases.

Pattern Code
Send auth token headers: { Authorization: 'Bearer ' + token }
Send form data body: new FormData(formEl) (no Content-Type header needed)
Abort a request const ac = new AbortController(); fetch(url, { signal: ac.signal })
Read plain text const text = await response.text()
Download a blob const blob = await response.blob()

Use AbortController to cancel in-flight requests — useful in React useEffect cleanup to prevent state updates on unmounted components.

Fetch vs Alternatives

Know when to reach for a library versus the native Fetch API.

Tool Best For Trade-off
fetch() Simple requests, no extra dependencies Verbose error handling, no interceptors
axios Complex apps needing interceptors, retries External dependency (~15 kB gzipped)
SWR / React Query Data fetching in React with caching Framework-specific, more setup
tRPC Full-stack TypeScript with end-to-end types Requires matching server setup

Tip: For Next.js App Router, prefer the built-in fetch extended by Next.js — it supports cache and next.revalidate options directly, enabling server-side data fetching with ISR.

JavaScript Storage