AniUI Academy

Fetching Data from the Web

Connect your JavaScript to real servers using fetch(), async/await, JSON parsing, HTTP methods, status codes, and network error handling.

12 min read

When you visit a weather website, check a live sports score, or send a message in a chat app, how does the web page get fresh information without reloading the whole screen?

The answer is fetching data from APIs.

JavaScript includes a built-in function called fetch() that acts like a messenger. It sends a message over the internet to a server, waits for the server to reply, and brings back fresh data for your page to display.

  1. Step 1

    1. Call fetch(url)

    Sends an HTTP request across the internet to the server

  2. Step 2

    2. Receive Response

    Server returns headers and status code (e.g., 200 OK)

  3. Step 3

    3. await response.json()

    Reads and converts raw JSON text into a live JS object

  4. Step 4

    4. Update UI

    Renders fresh data on screen without reloading the page

The 4-step lifecycle of fetching network data in JavaScript

The anatomy of an HTTP request

When your browser talks to a server, it uses HTTP (HyperText Transfer Protocol). Every request is made up of a method, a URL, a set of headers and sometimes a body. The request specifies a method, which tells the server what you want to do:

GET Method

Retrieve data from the server (read-only, default for fetch).

POST Method

Send new data to the server to create something (e.g. submitting a comment).

PUT / PATCH Methods

Update or modify an existing resource on the server.

DELETE Method

Remove a resource from the server.

Your first fetch request

fetch() uses Promises under the hood, so it works naturally with async and await:

async function loadUserData() {
  try {
    // 1. Send request over the network
    const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
 
    // 2. Check if the server responded successfully (status 200-299)
    if (!response.ok) {
      throw new Error(`Request failed with status ${response.status}`);
    }
 
    // 3. Parse the incoming JSON text into a JavaScript object
    const user = await response.json();
 
    console.log("User Name:", user.name);
    console.log("User Email:", user.email);
  } catch (error) {
    console.log("Failed to fetch user:", error.message);
  }
}
 
loadUserData();

Let us step through what happened:

  1. fetch(...) starts the network call and returns a response promise.
  2. response.ok is true if the HTTP status code is between 200 and 299.
  3. response.json() reads the response body stream and converts the raw text into a real JavaScript object.

Sending data with POST

To send data (like submitting a form or posting a comment), pass an options object as the second argument to fetch():

async function createNewPost() {
  const newPostData = {
    title: "Learning JavaScript",
    body: "This post was sent from the browser with fetch().",
    userId: 1,
  };
 
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(newPostData), // Convert object to JSON string
    });
 
    if (!response.ok) {
      throw new Error("Server rejected post creation");
    }
 
    const createdPost = await response.json();
    console.log("Created successfully with ID:", createdPost.id);
  } catch (err) {
    console.log("Post failed:", err.message);
  }
}

Notice JSON.stringify(newPostData). Over the network, servers speak raw text, not live JavaScript objects. JSON.stringify() serialises our object into a string, and Content-Type: application/json tells the server how to read it.

Try it yourself

This makes a real network request against a free mock API (jsonplaceholder.typicode.com). Change the id in the URL to something invalid like 9999 and watch the error path run.

Try it yourself
Loading playground...

Common pitfalls

  1. Forgetting await on .json(): response.json() returns a Promise. If you omit await, the variable holds a still-pending Promise rather than your data, and logging it prints Promise { <pending> }.
  2. Assuming fetch rejects on 404: A 404 Page Not Found is a successful network response returning a 404 status. Always check response.ok.
  3. Handling Offline Users: Always wrap fetch() in try...catch. If a user loses Wi-Fi connection, fetch() will throw a TypeError: Failed to fetch.
  4. Showing Loading States: Before calling fetch(), set a loading spinner or text (loading = true). When done (inside finally), turn it off (loading = false).

What to remember

fetch() connects browser JavaScript to web servers. Use await fetch(url) to send a request, check response.ok before trusting the result, parse the body with await response.json(), send data with POST and JSON.stringify(), and wrap the whole thing in try...catch for the times the request never arrives.

Check yourself

4 questions · pass 3/4 to unlock Scope and Closures

up to 50
  1. 1.What does the fetch() function return?

  2. 2.Why must you call await response.json() after fetch()?

  3. 3.Does fetch() reject its Promise when a server returns a 404 or 500 status code?

  4. 4.What HTTP method should you use when sending new data to be created on a server?

4 left to answer