Skip to main content

Command Palette

Search for a command to run...

APIs & Fetch API in JavaScript – Getting Data From the Web

Updated
5 min readView as Markdown

Over the past few days, I've learned how JavaScript works with objects, arrays, JSON, and browser storage.

Today, I explored APIs and the Fetch API.

Until now, most of the data I worked with was written directly inside my JavaScript code.

APIs change that.

They allow my application to communicate with external servers and retrieve real-world data such as users, products, weather information, posts, and much more.

Let's dive in.


What is an API?

API stands for Application Programming Interface.

An API provides a way for different software systems to communicate with each other.

For example:

Frontend
    ↓
   API Request
    ↓
Backend / Server
    ↓
   API Response
    ↓
Frontend

The frontend doesn't need to know how the server internally works.

It simply sends a request and receives a response.


What is an HTTP Request?

When a browser communicates with a server, it commonly uses HTTP.

Some common HTTP methods are:

Method Common Purpose
GET Retrieve data
POST Create/send data
PUT Replace data
PATCH Update part of data
DELETE Remove data

Today, I'll mainly focus on GET requests.


What is Fetch API?

The Fetch API provides a modern way to make HTTP requests from JavaScript.

Basic example:

fetch("https://example.com")

fetch() returns a Promise because the response doesn't arrive immediately.

This leads us into asynchronous JavaScript.


Understanding Asynchronous JavaScript

Some operations take time to complete.

For example:

  • Fetching data from a server

  • Reading files

  • Waiting for a timer

  • Communicating with a database

JavaScript doesn't need to stop everything while waiting.

Instead, asynchronous operations allow other code to continue running.

Example:

console.log("Start");

setTimeout(() => {
    console.log("Finished");
}, 2000);

console.log("End");

Output:

Start
End
Finished

The timer runs asynchronously.


What is a Promise?

A Promise represents the eventual result of an asynchronous operation.

A Promise can be in one of three states:

  • Pending

  • Fulfilled

  • Rejected

Conceptually:

Pending
   ↓
Fulfilled

or

Pending
   ↓
Rejected

fetch() returns a Promise.


Using Fetch

A basic GET request looks like:

fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => {
        return response.json();
    })
    .then(data => {
        console.log(data);
    });

Here we're requesting user data from an API.


Understanding response.json()

The response returned by fetch() isn't immediately the JavaScript object we want.

We use:

response.json()

to parse the JSON response.

It also returns a Promise.

That's why we use another .then().


Handling Errors

Network requests can fail.

We can handle errors using .catch().

fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => response.json())
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.error("Something went wrong:", error);
    });

This prevents errors from being silently ignored.


Checking HTTP Response Status

A failed HTTP request doesn't always cause fetch() itself to reject.

For example, a server might respond with a 404 status.

We can check:

fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => {

        if (!response.ok) {
            throw new Error("Request failed");
        }

        return response.json();
    })
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.error(error);
    });

The response.ok property helps us check whether the HTTP response was successful.


Async & Await

Modern JavaScript provides a cleaner way to work with Promises using:

  • async

  • await

Example:

async function getUsers() {

    const response = await fetch(
        "https://jsonplaceholder.typicode.com/users"
    );

    const data = await response.json();

    console.log(data);
}

getUsers();

await pauses execution inside the async function until the Promise settles.

It makes asynchronous code easier to read.


Handling Errors With try...catch

When using async/await, we can handle errors using try...catch.

async function getUsers() {

    try {

        const response = await fetch(
            "https://jsonplaceholder.typicode.com/users"
        );

        if (!response.ok) {
            throw new Error("Failed to fetch users");
        }

        const data = await response.json();

        console.log(data);

    } catch (error) {

        console.error(error);

    }
}

getUsers();

This is a common pattern in modern JavaScript applications.


Fetching and Displaying Data

The real power of APIs comes when we combine them with the DOM.

HTML:

<ul id="users"></ul>

JavaScript:

const usersList = document.querySelector("#users");

async function getUsers() {

    const response = await fetch(
        "https://jsonplaceholder.typicode.com/users"
    );

    const users = await response.json();

    users.forEach(user => {

        const li = document.createElement("li");

        li.textContent = user.name;

        usersList.appendChild(li);

    });
}

getUsers();

Now the API data is dynamically displayed on the webpage.

This is where everything I've learned so far starts coming together:

API → JSON → JavaScript → DOM


API Response Flow

The complete process looks like:

User
  ↓
Frontend
  ↓
fetch()
  ↓
HTTP Request
  ↓
Server / API
  ↓
JSON Response
  ↓
JavaScript
  ↓
DOM
  ↓
Webpage

Understanding this flow is fundamental to modern web development.


Best Practices

✔ Always handle possible request failures.

✔ Check response.ok before processing the response.

✔ Use async/await when it makes asynchronous code easier to understand.

✔ Don't assume external API data will always have the expected structure.

✔ Keep API logic separate from DOM manipulation when possible.

✔ Never expose private API keys or secrets in frontend JavaScript.


My Biggest Takeaway

Today was a major step in my JavaScript journey.

Until now, I was mainly working with data that already existed inside my application.

With APIs and the Fetch API, I can now communicate with external servers and retrieve real data.

The most important flow I learned today is:

Request → Server → Response → JSON → JavaScript → DOM

This connects many of the concepts I've learned over the last few days and brings them much closer to real-world web development.

1 views

100 Days of Code: My Journey to Becoming a Full Stack Developer

Part 45 of 50

Welcome to my 100 Days of Code journey! In this series, I'll document my daily progress as I learn Full Stack Web Development from the ground up. Every post will cover what I learned, challenges I faced, mistakes I made, and the projects I built. My goal is not just to complete 100 days but to become a better developer through consistency, discipline, and learning in public. Topics I'll cover include: • Git & GitHub • HTML, CSS & JavaScript • React.js • Node.js & Express • MongoDB • APIs • Real-world Projects • AI tools for Developers Whether you're just starting out or revising your fundamentals, I hope this journey helps you learn alongside me. Let's build, learn, and grow together! 🚀

Up next

HTTP Methods & Sending Data With Fetch API

Yesterday, I learned how to use the Fetch API to retrieve data from external servers using GET requests. Today, I explored how applications can also send, update, and delete data using different HTTP

More from this blog

T

TheSaurceCode

73 posts

Documenting my journey to becoming a Full Stack Developer through daily blogs, coding challenges, projects, tutorials, and lessons learned. Learn, build, and grow with me