</>
Skip to content
JavaScript lessons (48/64)

JavaScript — Fetch

One function for the network

const res = await fetch("https://api.github.com/users/octocat");

fetch returns a promise resolving to a Response object — headers arrived, body maybe not yet.

Reading JSON (two-step!)

const res = await fetch(url);
const data = await res.json();     // parse body → JS value
console.log(data.name);

.json() is also async (body streams in). Sibling methods: .text(), .blob() for files.

The #1 gotcha: fetch only rejects on network failure. A 404 or 500 still resolves! Check manually:

if (!res.ok) {                       // status outside 200–299
    throw new Error(`HTTP ${res.status}`);
}

Wrap it once, reuse forever:

async function getJSON(url) {
    const res = await fetch(url);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
}

Sending data — POST

const res = await fetch("/api/todos", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ title: "Learn fetch", done: false }),
});
MethodIntent
GETread (default)
POSTcreate
PUT/PATCHupdate
DELETEremove

JSON bodies must be stringified and declared via Content-Type — the two most-forgotten lines in web dev.

Full CRUD sketch

async function crudDemo() {
    // CREATE
    const created = await getJSON("/api/todos", {
        method: "POST", body: JSON.stringify({ title: "new" })
    });

    // READ one
    await getJSON(`/api/todos/${created.id}`);

    // UPDATE
    await fetch(`/api/todos/${created.id}`, {
        method: "PATCH",
        body: JSON.stringify({ done: true })
    });

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

Loading states & UI pattern

list.innerHTML = "Loading…";
try {
    const todos = await getJSON("/api/todos");
    list.innerHTML = todos.map(t => `<li>${t.title}</li>`).join("");
} catch (e) {
    list.textContent = `Couldn't load: ${e.message}`;
} finally {
    spinner.hidden = true;
}

Every real app: loading → success/error UI. Plan all three states before coding the request.

Headers, auth & query params

fetch(url, { headers: { Authorization: `Bearer ${token}` } });

// building query strings safely:
const qs = new URLSearchParams({ page: 2, q: "js" });
fetch(`https://x.dev/search?${qs}`);
// https://x.dev/search?page=2&q=js   ← encoded automatically

CORS in one paragraph

Browsers block reading cross-origin responses unless that server sends permissive headers (Access-Control-Allow-Origin). When your fetch mysteriously errors while curl works — it's CORS, a server-side fix, not your bug.

Mini Practice

  1. Fetch GitHub API user; print name/avatar with full error handling
  2. POST to jsonplaceholder.typicode.com; log returned fake id
  3. Build getJSON wrapper; prove it throws on a 404 URL
  4. Paginate with URLSearchParams; fetch pages 1-3 sequentially
  5. Wire loading/error/success states around any public API

Next: window → (browser APIs stretch)

Related Topics

Frequently Asked Questions about Fetch

What is Fetch in JavaScript?

Fetch is a fundamental concept in JavaScript. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Fetch?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Fetch.

Why is Fetch important in JavaScript?

Fetch is essential for JavaScript development. Understanding this concept will help you write better code and solve real-world problems more effectively.