How to make API calls with Javascript

tq-bit - Dec 28 '20 - - Dev Community

While most of the APIs nowadays are well documented and aligned with modern standards, it is still crucial to understand what's going on behind the curtains.

To deep dive into how to actually use an API, you need to consider that the process depends highly on the use case of your website. To give you an insight in the operations to be done, we will build a simple Pokedex with an online service delivering the data to us. Parts of the code are not on a beginners level, so I will put in references to the Mozilla Development Network on subtopics where one might easily loose the red thread.

1. What is an API?

An Application Programming Interface is the middleman between your website / webapp in the browser and its data. It does neither display them to a user, nor directly handles the database queries on your backend server.

Technically speaking, an API a piece of logic on your serverside code that handles browser - or client - requests and responses back to it. Take this statement with a grain of salt, some articles on the internet can have a slightly different explanation.

An API is a part of a webserver that deals with requests and responses

The most common practice of how to interact with it is with an http request, the top dog in internet communication. Http is not related to any tech stack, it works the same way over all programming languages.

For the rest of the article I will take URLs and endpoints as synonymous. Behind each of those endpoints. Behind each of this endpoints sits a unique business logic that queries a database based on your input, processes the result and sends it back to the client. Their structure is similar - one is put together by combining:

  • A root-url, often the domain of the website, followed by /api/v1
  • The endpoint's path coming after the root, like /api/v1/path/endpoint
  • An optional query for more specific requests.

A full endpoint's url that returns data and we will use later in this article is:

https://pokeapi.co/api/v2/pokemon/pikachu/

2. Why an API?

The internet is big, but you probably knew that before. To make things easier, standards are being introduced and improved. One of the more popular ones related to the topic at hand is the usage of a REST API.

In a nutshell, an API - given it is properly engineered - empowers you to view your webapp / website distinctly from all its data and backend logic. You can consume the same data in your website, a related mobile app or serve it over another standalone webservice. Using an API also empowers web engineers to focus on their domain of knowledge, either the frontend or the backend, while having to commit to only the interface connecting the two.

An API empowers you to decouple the client from the server's business logic

So much for the prequel, let's get started coding.

3. How it's done

It's now time for us to build a small project around PokeApi. PokeApi is an educational service providing open and free data around Nintendo's famous handheld game.

The final app will look like this, simply and clean:

00_Pokeapi_Project_Done-min

Planning out and setup of the necessary files

Before jumping in, let's take a step back and think about what we'd like to achieve:

  1. How to get data from an API
  2. How to consume them in HTML / Javascript

Simple enough. Let's now try and rephrase this as features:

  • We will create a simple user interface that initially shows an empty list
  • We will send an HTTP - request to the PokeApi and fill the list up with Pokemon data.
  • This list will then be displayed - the user is happy and we learned the lesson.

Write the HTML index and add some styles

I've prepared a Jsfiddle for you to follow along. If you're after the final version, you can find it at the end of the article

https://jsfiddle.net/q_bit/o8ydu3xp/

  • We're creating a basic html skeleton, holding a heading, a button and a list.
  • The styles center our content, add basic responsiveness and incorporate icons.

If you prefer a local setup, launch your favorite code editor, such as Atom or VSCode and create three files. Fill the index and style - files up with the code from the fiddle and let's go.

FILE CONTENTS
index.html Holds the list for our Pokedex
style.css Holds the styling for our user interface
main.js Holds the code to make an API request

Write the Javascript to GET data

While there is more than one way to achieve this, I will present you one of the more contemporary ones that is available in all modern browsers - the window method fetch.

Note that fetch is not available by default on node.js. If you are following along with node, you need to install an npm package called isomorphic-fetch. The functionality is the same as you would expect it in the browser.

Asynchronous programming

Due to the asynchronous nature of Javascript, we will use a Javascript utility method called Promises. If we did not do that, functions would fail as they're missing the data they require to work. Why? Because calling a server takes a moment, while Javascript code by default keeps running and does not wait for still pending operations to finish. For reference, you might want to take a look into this article (warning: You'll leave dev.to) and MDN's Using Async/Await in case you have doubts on what's happening.

Start by adding the following code to your main.js file:

(() => {
 // Query the button dom element and assign the root path
 const buttonRefresh = document.querySelector('#refresh-pokedex-list');
 const apiRoot = 'https://pokeapi.co/api/v2';

 // Add an event listener to the button and bind the function
 buttonRefresh.addEventListener('click', async () => {
  const url = apiRoot + '/pokemon';
  const response = await fetch(url);
  const data = await response.json();
  console.log(data);
 });
})();
Enter fullscreen mode Exit fullscreen mode

After that's done, open your browser's developer tools with crtl+ shift + L (cmd+etc for mac-users) then click the button 'Refresh'. You should see the following:

01_Pokeapi_Request_Console-min

There's the requested data. What you can see in the console is a JSON object returned by the API, holding the desired data in its .results - array. How'd it get there? When clicking the button, line per line, the following happens:

  1. We define the endpoind we want to receive data from. That is: https://pokeapi.co/api/v2/pokemon. If you've tried to open it with your browser earlier, you've already seen the raw JSON.
  2. We are using fetch() on this endpoint and open a data stream.
  3. As soon as the data stream has been received, we convert it into JSON data.
  4. Then, we're using the browser's console.log() to make that data visible.

So far so good. Now let us refactor this code a little to make it more readable

Refactoring the fetch - code

Instead of doing everything in the event listener callback function, let's create a separated function. While we are at it, we will also add a query to our endpoint string. You might have noticed the PokeApi has added this automatically to our previous request. Sending a lot of data at once, perhaps even irrelevant chunks, is putting unnecessary pressure on the server.

Modify your main.js file so it looks more like this:

(() => {
 // Define the relevant variables
 const buttonRefresh = document.querySelector('#refresh-pokedex-list');
 const apiRoot = 'https://pokeapi.co/api/v2';

 // Define the relevant functions
 getPokemonList = async (limit) => {
  const url = apiRoot + '/pokemon?limit=' + limit;
  const response = await fetch(url);
  const data = await response.json();
  return data;
 }

 // Attach the functions to the DOM elements
 buttonRefresh.addEventListener('click', async () => {
  const data = await getPokemonList(9);
  console.log(data);
 });
})();
Enter fullscreen mode Exit fullscreen mode

Now we have a solid base to build on. Let's continue by binding the received data.

Write the code to create the DOM elements

It's time to give life to our user interface. Javascript allows us to manipulate the DOM the browser creates. You might have noticed that in the index.html file, there's no markup yet that indicates some kind of list or table. The structure we will create for that now looks like this in plain HTML. You can add it to the index, inside the div - tag with the id if 'pokedex-app' to get an idea of how it'll look like later.

<ul class="pokedex-list">
 <li class="pokedex-list-item">
  <span>Pokemon 1</span>
  <i class="fas fa-chevron-right"></i>
 </li>
 <li class="pokedex-list-item">
  <span>Pokemon 2</span>
  <i class="fas fa-chevron-right"></i>
 </li>
 <li class="pokedex-list-item">
  <span>Pokemon 3</span>
  <i class="fas fa-chevron-right"></i>
 </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Use the document - object to create new elements

Instead of writing the html in a static file, we can use a browser feature to dynamically change the appearance of our website - without reloading the whole page. If you'd like to read more on the DOM and its functionality, here's the reference.

With the following code, we will now inject elements into our website that hold the fetched data instead of just displaying them in the console. As the operation is rather long, I have added the comments directly within the code

Add these to your main.js file in the respective section:

  • Put this above the getPokemonList - function. capitalize() is a convenience function to convert the first letter of each pokemon into uppercase.
// Join the first char of a string, uppercase, with the rest of it
const capitalize = string => {
 const stringLength = string.length;

 return string.charAt(0).toUpperCase() +
  string.split('').splice(1, stringLength - 1).join('');
};
Enter fullscreen mode Exit fullscreen mode
  • Then, put this below the getPokemonList - function. createPokemonList() will take in the data fetched from the PokeApi and build up a element which is then added to the DOM node.
createPokemonList = data => {
 const pokedexListLength = data.length;
 const pokedexApp = document.querySelector('#pokedex-app');
 let pokedexList = document.querySelector('.pokedex-list');

 // Remove the list from the app, if it exists
 if (pokedexList) {
  pokedexApp.removeChild(pokedexList);
 }

 // Create the unordered list element and reassign the pokedexList variable
 pokedexList = document.createElement('ul');
 pokedexList.classList.add('pokedex-list');

 // Now create a list item for each item in the data array
 for (let i = 0; i < pokedexListLength; i++) {
  // Create the necessary items
  const pokedexItem = document.createElement('li');
  const pokedexItemName = document.createElement('span');
  const pokedexItemIcon = document.createElement('i');

  // Capitalize the pokemon's name and get its url
  const pokemonName = capitalize(data[i].name);
  const pokemonUrl = data[i].url;

  // Add the pokemon name and the ID to the created element
  pokedexItem.id = pokemonUrl;
  pokedexItemName.innerHTML = pokemonName;

  // Add the relevant classes
  pokedexItem.classList.add('pokedex-list-item');
  pokedexItemIcon.classList.add('fas', 'fa-chevron-right');

  // Put the items together 
  pokedexItem.appendChild(pokedexItemName);
  pokedexItem.appendChild(pokedexItemIcon);

  // Then, add the item to the list 
  pokedexList.appendChild(pokedexItem);
 }

 // Finally, add the pokedexList back to the app
 pokedexApp.appendChild(pokedexList);
};
Enter fullscreen mode Exit fullscreen mode
  • Finally, modify the event listener function to make it look like this:
buttonRefresh.addEventListener('click', async () => {
 const data = await getPokemonList(9);
 createPokemonList(data.results);
});
Enter fullscreen mode Exit fullscreen mode

Wrap up: The final result

If everything went well, upon the click of the 'Refresh' - button, your application will now present you the first nine Pokemon entries of the Kanto Pokedex.

The key takaways you should have gotten till here are:

  • We have fetched some data, namely those nine pokemon entries, from an API.
  • We have bound these elements to our UI and dynamically built up a list.
  • On the way, we got a few hints on why we need to consider asynchronous programming when communicating with a server.
  • Perhaps you've also gotten an idea on how to improve, maybe to add a detail component that shows a single pokemon and its moveset? Or a searchbar? Let loose your imagination, jump into the PokeApi docs and give it a shot. You can use the final code in the below Jsfiddle as a starting point.

https://jsfiddle.net/q_bit/mueko0dz/1/

Originally published @ https://blog.q-bit.me/make-api-requests-with-javascript/

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .