How to make HTTP requests using Fetch API and Promises

Jan 8 · 7 min read
Photo by Markus Spiske on Unsplash

In this guide, I’m going to teach you how to render a list of items from an API endpoint. You will learn how to make a HTTP request using Fetch API, learn the basics of a native JavaScript Promise object and how to chain Promises using the Promise.prototype.then() method.

Before we begin the tutorial, let’s first learn about the Fetch API and what exactly are Promises.


What is Fetch API?

The Fetch API is a simple interface for fetching resources. Fetch allows us to make network request and handle responses easier than our old friend XMLHttpRequest(XHR). One of the main differences is that Fetch API uses Promises, which provides a way to avoid callbacks hell and boilerplate heavy code that XMLHttpRequest(XHR) provides.

The fetch function takes one mandatory argument, which is the path to the resource you want to fetch and returns a Promise that resolves to the Response of that request.


What are Promises?

The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

Promises provides us a simpler alternative to executing, composing and managing asynchronous operation compared to the traditional callback-bases approach.

When working with Promises, we must be aware of what it’s current state. There are three states, Pending, Fulfilled and Rejected.

When a Promise is Pending, it can transitioned to either Fulfilled or Rejected. Once a Promise transitions to either Fulfilled or Rejected, it cannot transition to any other state and it’s value will not change as well.

When a Promise is Fulfilled, this means the asynchronous operation has completed and the Promise has a value. When a Promise is Rejected, this means the asynchronous operation has failed, and the Promise will never be fulfilled.


Using Fetch API and Promises

We will now work on a simple example where we will use the Fetch API and Promises in order to render a list that contains data from an API endpoint.

We will be using a public API that contains information from my favorite animation studio called Studio Ghibli https://ghibliapi.herokuapp.com/

Let’s begin by creating a index.html file that contains some basic information, in order to render a page.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Studio Ghibli</title>
</head>
<body>
<h1>Studio Ghibli Characters</h1>
<div id="main"></div>
<script src="index.js"></script>
</body>
</html>

We will not be making any further changes to this file. If I open this index.html page, I should see the following

index.html

Let’s now create our index.js file, which is referenced inside our html file.

<script src="index.js"></script>

Inside our index.js file, let’s try to fetch data from the ghibliapi and let’s log the response

const fetchPromise = fetch(“https://ghibliapi.herokuapp.com/people");console.log(fetchPromise);
Pending Promise

When making an HTTP request as an asynchronous operation, fetch will not return any data. However it will return a response promise. When we log the response, it will show this Promise is in pending state. This means that the HTTP response we are expecting will get back eventually, but at the time of logging, this response was not ready to be logged.

Our Promise is in pending state, it can now transition into a fulfilled state if everything goes well or a rejected state if there’s an error while fetching. Once the Promise is settled, it can’t no longer change state.

Let’s now move back to our example and learn on how we can extract some data from this response Promise object. We will use the Promise.prototype.then method in order to attach a callback once our Promise has been fulfilled.

const fetchPromise = fetch("https://ghibliapi.herokuapp.com/people");
fetchPromise.then(response => {
console.log(response);
});

We are logging the response, to see what information we receive from the API. If we go back to our browser and hit refresh we should get a response object with some information that includes headers, body, type and even status code.

Response Promise object fulfilled

Now that we know our API response is working, we want to move on and actually get the body of the response. We want to call the json() method on the response in order to get the response body in json format. This operation is also asynchronous. The json() method actually returns a Promise, so we will need to create a Promise chain.

We will pass the value we receive from the first Promise into our chain in order to do some operations. In this case, we are just passing the people object

const fetchPromise = fetch("https://ghibliapi.herokuapp.com/people");
fetchPromise.then(response => {
return response.json();
}).then(people => {
console.log(people);
});

Once you refresh your browser and check your logs, you will see a object with many keys that contain attributes of people in Studio Ghibli films.

API Response

As you can see, this object returns a good chunk of information. For the sake of this guide, we will focus on just displaying a person’s name. Let’s transform this object to only return names. A way to do that is to use the map() function. After we map, we will want to then join together each name with a new line.

const fetchPromise = fetch("https://ghibliapi.herokuapp.com/people");fetchPromise.then(response => {
return response.json();
}).then(people => {
const names = people.map(person => person.name).join("\n");
console.log(names);
});
Studio Ghibli Characters Logged in the Console

This is a great milestone!

We are now logging some names but how can we render this list of names in our html instead?

If we take a look at our HTML file, we have a <div> with an ID of main.

<div id="main"></div>

In order to render a list of names, we will target the main ID from our HTML and append the list of names we fetched. To do this we will use a HTML property called innerHTML. This innerHTML Element property allows us to set HTML inside a HTML element which we are going to do to the main element.

const fetchPromise = fetch("https://ghibliapi.herokuapp.com/people");// Target main element
const main = document.getElementById("main");
fetchPromise.then(response => {
return response.json();
}).then(people => {
const names = people.map(person => person.name).join("\n");
// Append names to main element
main.innerHTML = names;
});

Let’s head to our browser and refresh.

We have successfully fetched data from an API endpoint and rendered this data on the page. This is great, but there’s one problem … We can’t tell how many people are on this list.

Studio Ghibli Characters Rendered

What’s exactly is the issue? We appended a list of names, but the browser doesn’t know how to deal with a string of names other than rendering it in one line. We are missing some markup in order for our list of names to actually look like a list.

Let’s do some improvements to our code in order to render this list.

First thing we are going to do is move our names list into a function called listOfNames which will take the people object. We will also interpolate some markup in order to show that each person belongs to a list item. Our listOfNames will return an unordered list of all our names. We will finally assign this listOfNames to our main.innerHTML element.

const fetchPromise = fetch("https://ghibliapi.herokuapp.com/people");
const main = document.getElementById("main");
fetchPromise.then(response => {
return response.json();
}).then(people => {
main.innerHTML = listOfNames(people);
});
function listOfNames(people) {
const names = people.map(person => `<li>${person.name}</li>`).join("\n");
return `<ul>${names}</ul>`
}
List of rendered Studio Ghibli Characters
Studio Ghibli HTML Source Code markup

As you can see, our main div now has a unordered list of names and it renders like a list.

Another quick fix we can make here is showing some text when fetching data. When we reload the page, for a split second, our main div is empty. When fetching large amount of data from an api or when a connection is slow, you want to show the user that we currently loading some data. In order to do that we should have a placeholder in our main div until our fetch promises are fulfilled.

const fetchPromise = fetch("https://ghibliapi.herokuapp.com/people");
const main = document.getElementById("main");
// Loading Placeholder
main.innerHTML = "<p>Loading...";
fetchPromise.then(response => {
return response.json();
}).then(people => {
main.innerHTML = listOfNames(people);
});
function listOfNames(people) {
const names = people.map(person => `<li>${person.name}</li>`).join("\n");
return `<ul>${names}</ul>`
}

Here is an example of my page rendering in a slow connection

Showing example of Loading… text while fetching

Here is the final file with some light cleanup for readability and flexibility. https://github.com/ArmandoAmador/Fetch-API-Promises-Tutorial

const URL = "https://ghibliapi.herokuapp.com/people";const main = document.getElementById("main");
main.innerHTML = "<p>Loading...";
fetch(URL)
.then((response) => response.json())
.then((people) => main.innerHTML = getListOfNames(people));
const getListOfNames = (people) => {
const names = people
.map((person) => `<li>${person.name}</li>`)
.join("\n");
return `<ul>${names}</ul>`;
};

If you have any feedback, suggestions or just want to say hey, don’t hesitate to leave a message on the comment section below.

Thank you for reading.

Armando Amador

Written by

Software Engineer @Casper

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade