A Fulfilled Promise - Using The Fetch Api to Make Ajax Calls

Making partial web page updates by using fulfilled promises with fetch

by Iveta Karailievova Date: 26-12-2020 JavaScript fetch promise AJAX

In this article we talked about what AJAX calls are and how to use them in a traditional way, by using the XMLHttpRequest (XHR) object. In short, thanks to AJAX calls a web page can be partially updated without having to reload the whole content. This leads to better loading speeds, usability and nowadays is an indispensable part of modern web development. Now we will focus on a more modern approach, which is by using the fetch Web API. 

In this article, as an example, we will build a functionality which generates and diplays on our page random Rick and Morty characters. The only language we need to use is plain (vanilla) JavaScript, and the rest of the magic (the back end part) will be provided by the Rick and Morty REST API

Web APIs - what are they?

A Web API is an application programming interface for the Web. To put it simply, when you write code for a web page, you may use a web API, which makes your job way easier, for example, by providing the web browser with more the functionality, by simplifying complex functions or by simplifying the code’s syntax. One of those useful APIs is fetch, which helps us to make web requests in a more intuitive and simpler way.

What is the fetch API and why is it better than XHR?

It is a relatively new, native JavaScript API. Fetch API was introduced with ECMAScript 6, also known as ES6 and ECMAScript 2015, which was the second major revision to JavaScript. 

Fetch allows you to make asynchronous network requests to web servers similar to the XMLHttpRequest, but with the advantage of being more elegant, simpler and cleaner. The main difference between XHR and FECTH API is that the Fetch API uses Promises. Thanks to this, you will not have to deal with callback functions and the callback hell they could potentially result in. Also, with XMLHttpRequest, the syntax you need to use in  your code is more complex and thus might lead to errors. We can without doubt say that fetch API is an improvement over the traditional XMLHttpRequest method, and it offers us more features.

Although it is supported by most browsers today, it is not supported by Internet Explorer. So if you need your code to be compatible with IE, you should consider using polyfills. These are basically pieces of JavaScript code responsible for providing modern functionality on older browsers that do not natively support it.

How to use fetch – an example where we retrieve data from an API

As its name suggests, the fetch API provides an interface for fetching, obtaining resources. In order to call the fetch method, we need to supply one argument – the URL or path to the resource from which we want to get our response. 

Let’s get practical and start setting up our example. Here is the HTML markup:

in our index.html file, we put inside the <body> element:

<label for="number">Choose a number</label><br>
<input id="number" type="number" min="1" max="671" />
<img id="avatar" src="" alt="" />

and to make it a little more appealing, some CSS:

body {
background-color: coral;
color: grey;
font-size: xx-large;
text-transform: uppercase;
text-align: center;
font-family: Verdana, Geneva, Tahoma, sans-serif;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;

Next part - our vanilla JavaScript code with the fetch method

Let’s start with the easy part – creating constants to access the DOM elements which we are going to need:

// the inputValue allows us to access the value of the user's input, i.e. the chosen number
const inputValue = document.getElementById('number')
// this constant allows us to set the image to be displayed, by dynamically changing its "src" attribute
const avatar = document.getElementById('avatar') 

Since we want to be able to access different characters, so we keep the id part flexible – by using the replace() method. We will be supplying the "id" number dynamically, when the user changes the value of the input form.

const API_URL = 'https://rickandmortyapi.com/api/character/:id'
const URL = API_URL.replace(':id', id)

And now the interesting part – the fetch method returns a promise.

What is a JavaScript promise? 

Promises are a modern approach, a solution to the problems callback functions brought upon us. A promise is a placeholder for a value it will hold in the future, when the asynchronous request is resolved. To this promise, we can attach handlers, so that certain action is carried out in the case the promise is fulfilled and another if the promise is rejected. 

You could also think of a promise being in some ways similar to an event, but with the difference that a promise can only succeed or fail once, and that the result is final, meaning it cannot switch from being fulfilled to being rejected or vice-versa. 

In our case, the promise will at some point in the future contain the response, more precisely a Response object, a HTTP response. But careful – in order to be able to work with the actual data we received from the API, we first need to extract the response’s body, by using the json() method. This way, we parse the response into JSON. But, and this might seem somewhat confusing, the json() method returns another promise. This is because the reading of the stream containing the response is happening asynchronously.

We work with promises by assigning handlers to them, namely the then() and catch() method.

Promises can have one of the following states:

  • pending – this state is assigned automatically after the promise is created, it means so far the promise was neither fulfilled nor rejected;

  • fulfilled – the promise has been completed with success and the result we obtain is the value of the operation;

  • rejected – the promise has not been completed successfully, and the result we obtain is the reason why this happened (the error);

Handling errors when using fetch

in the case of fetch method, the fetch promises are rejected only when a network error is encountered (such as permissions issues, misconfigured CORS on the server-side, DNS lookup failure, etc.) HTTP responses with codes 4xx and 5xx are not network errors, so the catch() attached to the promise will not be fired in the case of these types of errors. That is why we need to check the fetch response’s ok property, like this:


it returns a Boolean value, being true if the response returned successfully.

By adding the following error-handling function, we can make sure that our errors are thrown and catched correctly, like in the case that the user chooses an id which is out of the APIs range of characters:

function handleErrors (response) {  
    if (response.ok) {
       return response
     throw new Error(response.statusText) 

So, now we have to chain all the promise then() methods, like this:

function getCharacter (id) {
  const URL = API_URL.replace(':id', id)
  // first we attach the error handler function

// next, if there was no error, we use the json method on our response object
    .then(function (response) {
      return response.json()

    // since the response.json() method used on a Response object returns another promise, we attach another then handler on the data we receive

    .then(function (data) {
      const newCharacterJSON = data
      // upon studying the response data structure, we know we need to access the "image" JSON key to get the image URL
      var imagePath = newCharacterJSON.image

      // now we set the src attribute of our image element to the URL from the reponse
      avatar.setAttribute('src', imagePath)
    // this part of the code allows us to correctly catch the errors which might have appeared, both errors of the original promise being rejected as well as the errors which are thrown by our handleErrors function
    .catch(function (err) {
      console.log('Something went wrong!', err)

Note: the response you get is not JSON, but an object with a series of methods that can be used depending on what you want to do with the information. Since the Rick and Morty API we’re using will return JSON to us, the returned response will have .json() method. We just need to call .json() on the response variable.

And finally, we need to think of a way of calling the function. We do this by adding an event listener to our input element. In this example we chose to use the change event, which gets triggered every time the value of the input field gets changed.

inputValue.addEventListener('change', function () {
const choosenNumber = inputValue.value

To take a better look on this solution, here you can see the full code and a working demonstration.


Even though the results we are getting might seem the same, using fetch API over XMLHttpRequest seems to be the correct way to write our code in the future, because it allows us to handle responses in a more organized way and spares us the trouble of descending into our little callback hell.

by Iveta Karailievova Date: 26-12-2020 JavaScript fetch promise AJAX hits : 6357  
Iveta Karailievova

Iveta Karailievova

Originally coming from a marketing background, decided to turn her life around and immerse herself into the wonderful exciting and most importantly – never boring world of technology and web development. Proud employee at MA-NO . Easily loses track of time when enjoying working on code. Big fan of Placebo, cats and pizza.


Related Posts

Starting with Bootstrap-Vue step by step

Today we will show you how to use BootstrapVue, describe the installation process and show basic functionality. The project’s based on the world's most popular CSS framework - Bootstrap, for building…

Creating simple CSS spinner-loader

In today's article we will show you how to animate a basic loader that spins when some predefined action is defined, such as loading an image. That can be used…

Validating HTML forms using BULMA and vanilla JavaScript

Today we are going to write about contact forms and how to validate them using JavaScript. The contact form seems to be one of the top features of every basic home…

How to use Parallax.js effect on your website

Today, we're going to write about the parallax effect, similar to parallax scrolling, and how to implement it to improve your landing page. In webdev, they say mobile first -…

How to make the website's dark mode persistent with Local Storage, CSS and JS

Recently we wrote about how to do a switchable alternative color mode or theme, a very useful and popular feature to websites. Today’s article is going to be about how…

Dark Mode on website using CSS and JavaScript

In today’s article we are going to learn how to build pretty much standard these days on the web pages and that is the alternative color mode and switching between…

JavaScript: Spread and Rest operators

In today’s article we are going to talk about one of the features of the ES6 version(ECMAScript 2015) of JavaScript which is Spread operator as well as Rest operator. These features…

Javascript: what are callbacks and how to use them.

Today we are going to learn about a concept that is widely used in javascript and that is used quite a lot by today's frameworks, libraries, especially NodeJS. This is…

HTTP Cookies: how they work and how to use them

Today we are going to write about the way to store data in a browser, why websites use cookies and how they work in detail. Continue reading to find out how…

The package managers npm and yarn: main differences

Npm and yarn are package managers that help to manage a project’s dependencies. A dependency is, as it sounds, something that a project depends on, a piece of code that…

The Javascript asign() method to merge and clone objects

In this article, we will be covering Object.assign()method in javascript in detail with examples. A javascript object is a collection of key-value pairs. Keys are also known as properties of object. Keys…

All the javascript functions and methods to manipulate arrays

This article will show that the prominent JavaScript array functions are .map(), .filter(), and .reduce(), and will then go through examples of instances in which .every() and .some() would save…

We use our own and third-party cookies to improve our services, compile statistical information and analyze your browsing habits. This allows us to personalize the content we offer and to show you advertisements related to your preferences. By clicking "Accept all" you agree to the storage of cookies on your device to improve website navigation, analyse traffic and assist our marketing activities. You can also select "System Cookies Only" to accept only the cookies required for the website to function, or you can select the cookies you wish to activate by clicking on "settings".

Accept All Only sistem cookies Configuration