JavaScript Fetch API

Load and send data over the network with fetch and async/await.

Lesson 51 of 56Advanced12 min read

fetch() is how JavaScript talks to the internet. With it you can load the latest weather, search a list of films, post a comment or save a score. Combine it with async/await and JSON and you can build apps that work with real, live data.

The services you fetch data from are called APIs (Application Programming Interfaces). An API is an address on a server that returns data instead of a web page. This lesson brings together several earlier topics, so if anything feels unfamiliar, the linked lessons are worth a quick review.

A GET request in three steps

JavaScript
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const user = await response.json();
console.log(user.name);
  1. fetch(url) sends the request and returns a promise for a Response object.
  2. response.json() reads the body of the response and parses the JSON. It also returns a promise, so await it too.
  3. Use the data, for example by displaying it on the page.

GET is the default type of request, used for reading data. You don't need to specify it.

Always check response.ok

fetch only rejects when the network itself fails, for example when the visitor is offline or the domain doesn't exist. A "404 Not Found" or "500 Server Error" still resolves successfully. Check the result yourself:

JavaScript
if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

response.status holds the status code: 200 means OK, 404 means Not Found and 500 means Server Error. Skipping this check is one of the most common fetch bugs, because the code then tries to read data that isn't there.

Sending data with a POST request

JavaScript
const response = await fetch(url, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ title: "Hello" }),
});
  • method is GET (the default), POST (create), PUT or PATCH (update) or DELETE.
  • headers tell the server what kind of data you're sending.
  • body is the data itself, converted to a JSON string.

Adding query parameters

Build URLs safely with URLSearchParams, which escapes spaces and special characters for you:

JavaScript
const params = new URLSearchParams({ q: "banana bread", page: 2 });
fetch(`https://api.example.com/search?${params}`);

JavaScript Fetch API Syntax

fetch patterns

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

await fetch(url, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(data),
});

JavaScript Fetch API Summary

  • fetch(url) sends a request and returns a promise for a Response.
  • Use await response.json() to read JSON data.
  • Always check response.ok, because HTTP errors don't reject the promise.
  • Send data with method: "POST", a JSON header and a stringified body.
  • Show loading and error states so visitors know what's happening.

JavaScript Fetch API Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

Load a user

This calls a public practice API, JSONPlaceholder. Change the 1 to another number from 1 to 10.

async function loadUser(id) {
  const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
  console.log("Status:", response.status);

  const user = await response.json();
  console.log(user.name, "|", user.email);
  console.log("Lives in", user.address.city);
}

loadUser(1);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 2Request the user. await waits for the response headers.
  2. Line 3200 means OK.
  3. Line 5Parse the JSON body.
  4. Lines 6 to 7Use the data like any object.
Example 2

A list with loading and error states

const button = document.querySelector("#load");
const statusEl = document.querySelector("#status");
const list = document.querySelector("#posts");

button.addEventListener("click", async () => {
  button.disabled = true;
  statusEl.textContent = "Loading…";
  list.replaceChildren();

  try {
    const res = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5");
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const posts = await res.json();

    for (const post of posts) {
      const li = document.createElement("li");
      li.textContent = post.title;
      list.append(li);
    }
    statusEl.textContent = `Loaded ${posts.length} posts ✅`;
  } catch (error) {
    statusEl.textContent = "Couldn't load posts: " + error.message;
  } finally {
    button.disabled = false;
  }
});
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 6 to 8Show a loading state and clear old results.
  2. Lines 11 to 12Request and check the status.
  3. Lines 15 to 20Turn data into list items with textContent (safe from injected HTML).
  4. Lines 21 to 22Friendly error message.
  5. Lines 23 to 25Always re-enable the button.
Example 3

Sending data with POST

JSONPlaceholder pretends to save it and sends back the new item with an id.

async function createTodo(title) {
  const res = await fetch("https://jsonplaceholder.typicode.com/todos", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ title, completed: false }),
  });

  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const saved = await res.json();
  console.log("Saved with id", saved.id, "→", saved.title);
}

createTodo("Learn fetch").catch(err => console.log("Error:", err.message));
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 3 to 5Method, headers and a JSON body.
  2. Line 8Check for server errors.
  3. Lines 9 to 10The server replies with what it saved.

Common JavaScript Fetch API Mistakes

Forgetting to await response.json()

Don't
const res = await fetch(url);
const data = res.json();     // a Promise!
console.log(data.name);      // undefined
Do
const data = await res.json();

Assuming fetch rejects on 404

Don't
try {
  const res = await fetch("/missing");
  const data = await res.json(); // crashes on an HTML error page
} catch (e) { … }
Do
const res = await fetch("/missing");
if (!res.ok) throw new Error(`HTTP ${res.status}`);

Putting secret API keys in front-end code

Don't
fetch(`https://api.paid.com/data?key=sk_live_123456`);
Do
// call your own server, which keeps the key secret and calls the paid API
fetch("/api/data");

Anyone can read your JavaScript in the browser. Keep secrets on a server.

JavaScript Fetch API in Real Projects

Real apps are built on fetch

Weather widgets, live sports scores, social feeds, "load more" buttons, search suggestions, payment forms and dashboards all fetch JSON from APIs. You now know the complete pattern: request → check → parse → render → handle errors.

JavaScript Fetch API Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Read the JSON body.

const res = await (url);
const data = await res.();
Multiple choicemedium

What does fetch do when the server replies with 404?

Multiple choicemedium

Which option sends JSON data to a server?

Fix the bughard

getTitle(1) should return the title of todo 1 ("delectus aut autem") and log it. Fix the function.

async function getTitle(id) {
  const res = fetch(`https://jsonplaceholder.typicode.com/todos/${id}`);
  const todo = res.json();
  return todo.title;
}

getTitle(1).then(t => console.log(t));
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • getTitle(1) returns the title

JavaScript Fetch API Quiz

3 questions to check what you learned.

  1. What does response.status 200 mean?

    • Not found
    • Server error
    • Redirect
    • OK, meaning success
  2. Which HTTP method is used to create new data?

    • GET
    • POST
    • DELETE
    • HEAD
  3. Why use URLSearchParams to build query strings?

    • It correctly escapes spaces and special characters
    • It's faster
    • fetch requires it
    • It adds an API key

JavaScript Fetch API Challenge

Count completed todos

Write async function countDone(userId) that:

  1. Fetches https://jsonplaceholder.typicode.com/todos?userId= + userId
  2. Checks response.ok and parses the JSON
  3. Returns how many todos have completed === true

Then log User 1 completed 11 todos.

ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • countDone(1) resolves to 11
  • Checks response.ok
  • Logs the summary