How to Use the Fetch API in JavaScript: Complete Guide with Examples

Muhaymin Bin Mehmood

Muhaymin Bin Mehmood

·
4 min read
Published Dec 9, 2024
Updated about 3 hours ago
Learn How to Use the Fetch API in JavaScript Banner Image
7 min read
633 words
15 sections7 code blocks

The Fetch API is the modern, built-in way to make HTTP requests in JavaScript. It replaces the older XMLHttpRequest with a cleaner, promise-based interface that works in every modern browser and in Node.js (version 18 and above).

This guide walks you through everything from a basic GET request to advanced patterns like timeouts, request cancellation, and authentication — with copy-paste examples you can use today.

What Is the Fetch API?

The fetch() function makes an HTTP request and returns a Promise that resolves to a Response object. Because it is promise-based, it pairs naturally with async/await.

JavaScript
const response = await fetch("https://api.example.com/users");
const data = await response.json();
console.log(data);

Two behaviours trip up almost every beginner:

  • Fetch reads the response in two stages — first you get the Response (status and headers), then you call .json() or .text() to read the body.
  • Fetch only rejects on network failure — not on HTTP errors like 404 or 500. You must check response.ok yourself.

Making a GET Request

A GET request retrieves data. Always check response.ok so server errors do not slip through silently:

JavaScript
async function getUsers() {
  const res = await fetch("https://api.example.com/users");
  if (!res.ok) throw new Error(`HTTP error ${res.status}`);
  return res.json();
}

Making a POST Request

To send data, pass a second argument with method, headers, and a body. Remember to JSON.stringify() the payload:

JavaScript
async function createUser(user) {
  const res = await fetch("https://api.example.com/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(user),
  });
  if (!res.ok) throw new Error(`HTTP error ${res.status}`);
  return res.json();
}

Handling Errors Properly

Because Fetch will not throw on 4xx or 5xx responses, wrap your calls so that HTTP errors are caught alongside network errors:

JavaScript
async function safeFetch(url, options) {
  try {
    const res = await fetch(url, options);
    if (!res.ok) {
      const message = await res.text();
      throw new Error(`Request failed (${res.status}): ${message}`);
    }
    return await res.json();
  } catch (err) {
    // Catches both network failures and the HTTP error thrown above
    console.error("Fetch error:", err.message);
    throw err;
  }
}

Setting a Timeout with AbortController

Fetch has no built-in timeout, so a slow server can hang your request forever. Use AbortController to abort after a set time:

JavaScript
async function fetchWithTimeout(url, ms = 8000) {
  const controller = new AbortController();
  const id = setTimeout(() => controller.abort(), ms);
  try {
    return await fetch(url, { signal: controller.signal });
  } finally {
    clearTimeout(id);
  }
}

Cancelling a Request

The same AbortController lets you cancel an in-flight request. This is essential for search-as-you-type, where you want to drop stale requests and avoid race conditions:

JavaScript
let controller;
function search(query) {
  controller?.abort();            // cancel the previous request
  controller = new AbortController();
  return fetch(`/search?q=${query}`, { signal: controller.signal });
}

Sending Headers, Auth, and Credentials

Add authentication tokens through headers, and use credentials: "include" when the API relies on cookies:

JavaScript
fetch("https://api.example.com/me", {
  credentials: "include",          // send cookies with the request
  headers: { Authorization: `Bearer ${token}` },
});

A common gotcha is CORS: cross-origin requests require the server to return the correct Access-Control-Allow-Origin header. CORS is enforced by the browser and cannot be fixed from your fetch() call alone.

Fetch vs Axios: Which Should You Use?

Axios is a popular library that wraps HTTP requests. Here is how it compares to the native Fetch API:

FeatureFetch APIAxios
Built in (no install)YesNo
Throws on HTTP errorsNo — check response.okYes, automatically
Automatic JSON parsingNo — call .json()Yes
Request timeoutManual (AbortController)Built in
Upload/download progressNoYes
Bundle size0 KB (native)~13 KB

Use Fetch for most projects — it is native, dependency-free, and more than capable. Reach for Axios when you need automatic error handling, request interceptors, or upload progress out of the box.

Common Fetch Errors and How to Fix Them

  • "Failed to fetch" — usually a CORS issue, a wrong URL, or the user is offline.
  • You get a Promise instead of data — you forgot to await res.json().
  • 404 or 500 not caught — you did not check response.ok.
  • "Unexpected token < in JSON" — the server returned HTML (often an error page). Read it with res.text() to debug.

Frequently Asked Questions

Does the Fetch API work in Node.js?

Yes. Fetch is available natively in Node.js since version 18 — you no longer need the node-fetch package.

Why doesn't fetch throw an error on a 404?

By design, fetch() only rejects its promise on network failures. A 404 or 500 is still a successful HTTP exchange, so you must check response.ok to detect status errors.

How do I send form data with fetch?

Pass a FormData object as the body and do not set the Content-Type header — the browser sets it automatically with the correct multipart boundary.

Can I track upload progress with fetch?

Not directly. Fetch does not expose upload progress events; use XMLHttpRequest or Axios if you need a progress bar.

Conclusion

The Fetch API handles the vast majority of network requests in modern JavaScript — GET and POST, JSON, error handling, timeouts, and cancellation — with zero dependencies. Master two habits: always check response.ok, and use AbortController for timeouts and cancellation. Do that, and you will handle real-world requests cleanly and reliably.

No comments yet. Be the first to comment!

Leave a Comment

2000 characters remaining

Related Articles

View all
Muhaymin Bin Mehmood

About Muhaymin Bin Mehmood

Front-end Developer skilled in the MERN stack, experienced in web and mobile development. Proficient in React.js, Node.js, and Express.js, with a focus on client interactions, sales support, and high-performance applications.