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

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:

```text
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:

```javascript
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:

```javascript
console.log("Start");

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

console.log("End");
```

Output:

```text
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:

```text
Pending
   ↓
Fulfilled

or

Pending
   ↓
Rejected
```

`fetch()` returns a Promise.

* * *

# Using Fetch

A basic GET request looks like:

```javascript
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:

```javascript
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()`.

```javascript
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:

```javascript
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:

```javascript
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`.

```javascript
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:

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

JavaScript:

```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:

```text
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.
