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

Mastering array sorting in JavaScript: a guide to the sort() function

In this article, I will explain the usage and potential of the sort() function in JavaScript.   What does the sort() function do?   The sort() function allows you to sort the elements of…

Infinite scrolling with native JavaScript using the Fetch API

I have long wanted to talk about how infinite scroll functionality can be implemented in a list of items that might be on any Web page. Infinite scroll is a technique…

Sorting elements with SortableJS and storing them in localStorage

SortableJS is a JavaScript extension that you will be able to use in your developments to offer your users the possibility to drag and drop elements in order to change…

What is a JWT token and how does it work?

JWT tokens are a standard used to create application access tokens, enabling user authentication in web applications. Specifically, it follows the RFC 7519 standard. What is a JWT token A JWT token…

Template Literals in JavaScript

Template literals, also known as template literals, appeared in JavaScript in its ES6 version, providing a new method of declaring strings using inverted quotes, offering several new and improved possibilities. About…

How to use the endsWith method in JavaScript

In this short tutorial, we are going to see what the endsWith method, introduced in JavaScript ES6, is and how it is used with strings in JavaScript. The endsWith method is…

What are javascript symbols and how can they help you?

Symbols are a new primitive value introduced by ES6. Their purpose is to provide us unique identifiers. In this article, we tell you how they work, in which way they…

Callbacks in JavaScript

Callback functions are the same old JavaScript functions. They have no special syntax, as they are simply functions that are passed as an argument to another function. The function that receives…

How to create PDF with JavaScript and jsPDF

Creating dynamic PDF files directly in the browser is possible thanks to the jsPDF JavaScript library. In the last part of this article we have prepared a practical tutorial where I…

How to make your own custom cursor for your website

When I started browsing different and original websites to learn from them, one of the first things that caught my attention was that some of them had their own cursors,…

Node.js and npm: introductory tutorial

In this tutorial we will see how to install and use both Node.js and the npm package manager. In addition, we will also create a small sample application. If you…

How to connect to MySQL with Node.js

Let's see how you can connect to a MySQL database using Node.js, the popular JavaScript runtime environment. Before we start, it is important to note that you must have Node.js installed…