Javascript HTTP Requests: All You Need To Know.

Javascript HTTP Requests: All You Need To Know.


Introduction.

As a Software Developer, you'll often need to send HTTP requests to get data from databases. This could be simple data like the number of votes a particular candidate has received in an online pool or even more complex data like a user's profile on a social media app. As a result of this, the knowledge of HTTP requests is quite indispensable in modern programming.

In this article, you'll learn about HTTP requests: What they are used for, Several ways they can be created, How to handle Errors and Data etc. Let's dive right in!


What is an HTTP Request And Why Will you Need to Send One?

HTTP simply means HyperText Transfer Protocol, It is a system that allows users to share data over the Internet despite not being connected physically; it is in fact the backbone of the Internet!

An HTTP Request is a query or message sent from a client(You) to a Host(server) to get, post or even remove data from the database. As an illustration, the code snippet below shows how an HTTP request can be sent to a host server using the fetch API, to upload a to-do item.

fetch("https://jsonplaceholder.typicode.com/todos", {

  method: "POST",
  body: JSON.stringify({
    userId: 1,
    title: "Fix my bugs",
    completed: false
  }),
  headers: {
    "Content-type": "application/json; charset=UTF-8"
  }

});

There are several reasons you may need to send an HTTP request, for example, you may need to write a program that fetches the products available in an online store server for display on the webpage, this is also illustrated in the code base below:

axios.get("https://jsonplaceholder.typicode.com/posts/products")
.then((response) => console.log(response.data))
.catch((error) => console.log(error));

In the above example, we have used the Axios API to get the product list from a host server. You'd notice the use of a Promises(Async programming) in the code snippet, you'd learn about Promises in the subsequent section.

You may also need to send an HTTP request to delete data from a database. An example of a request to delete a particular product from the database is illustrated in the code base below:

fetch("https://jsonplaceholder.typicode.com/posts/product1", 
   {  
   method: "DELETE"
   }
 )
.then(response => {  console.log(response.status); });

Do not fret if you don't understand these code snippets right now; these are just illustrations and will be explained in detail in the subsequent section.


HTTP Request And Promises.

You'd notice that the HTTP Requests thus far have been coupled to then, this is called a Promise in javascript. This is important because HTTP Requests belongs to a class of programming known as "Asynchronous Programming"

Asynchronous codes are also called non-blocking codes, they are codes that do not block programs from running other codes while being executed, in other words, they can run in the background and do not necessarily need to be completed before other codes can run, this is because of the event loop in javascript. When we send an HTTP Request, it is often important that we "wait" to receive the response before continuing our code execution. For example, we must get the list of available products from our online server before loading our online shop webpage, this is possible with the use of Promises.

A Javascript Promise is simply a Javascript Object that links producing codes and consuming codes together. In simpler terms, it's a piece of code that instructs the Javascript engine to wait for the response of a particular code(producing code) before executing another piece of code(consuming code). An example is Illustrated in the codebase below;

function doSomething(){
//send an HTTP request
}

doSomething()
  .then((result) => doSomethingElse(result))
  .then((newResult) => doThirdThing(newResult))
  .then((finalResult) => {
    console.log(`Got the final result: ${finalResult}`)
  })
  .catch(failureCallback);

In the piece of code above, a function that sends an HTTP request doSomething was created. While calling the function dosSomething, it was coupled with a then block which instructs the Javascript engine to execute the function doSomethingElse only upon getting the desired result(response of the HTTP request). The use of catch in the code snippet above is for error handling, this will be discussed in detail in the Error Handling section of this article.

Another way to use Promises is with the async/await syntax, async makes a function return a promise that can be chained to a then block, await on the other hand makes a function wait to resolve a promise before completing its execution. This is illustrated in the code block below

async function sendHttpRequest(){

const httpResponse= await fetch("https://jsonplaceholder.typicode.com/posts/products")

console.log(httpResponse) 

}
sendHttpRequest()

In the code block above the async/await syntax has been used to create an asynchronous function that will only log the httResponse variable when a response has been received from the server


HTTP Request Methods.

You may need to send an HTTP Request to a host server for several reasons, It could be to Get data from the server, To Add Data to the server, To Remove data from the server, to Modify data on the server or even to Replace Data on the server. A piece of instruction attached to an HTTP Request, that informs the Host server of the action needed to be completed is known as an HTTP Method.

There are several HTTP methods in modern Javascript, in this article you'll learn about the four major and common ones. It is worth mentioning that these methods are named in line with the function they perform as you'll see in the list below.

  • GET: This method is used to fetch specified data from a server.

  • POST: This method is used to upload/add a payload(data) to the server.

  • DELETE: As the name implies, this method removes a specified piece of data from the host server, permanently.

  • PUT: This method is used to replace specified data from the server with new data attached as a payload to the HTTP Request.

Examples of these methods in use with the fetch API is given in the code snippet below:

//GET Method

async function getRequest(url){

  const response= await fetch(url,{
    method: "GET",
    })
  //waits till the response is resolved

  return response

}

getRequest('http://your_backend_url/api/v1/download')
.then((response)=> response.json())//to extract the JSON body content from the response object recieved 
.then((data)=> console.log(data))
.catch((error)=> console.log("error message":error))
//POST Method

async function postRequest(url,data){

  const response= await fetch(url,{
    method: "POST"// or PUT,
    headers: {
      "Content-Type": "application/json",
      },
    body: JSON.stringify(data),// The "data" here is the payload we want to upload on the host server, this data type must match the content type in the header
   })

  return response

}
postRequest('http://your_backend_url/api/v1/upload',{name:"Javascript"}) 
.then((response)=>{

  if(!response.ok){
//to check if the ressponse receieved is okay i.e status code below 300
     throw new Error("Data Posting failed")
     }else{

     console.log("Positing successful")

      }

  }
.catch((error)=>console.log("Error message:"error)
//DELETE Method
async function deleteRequest(url,id){

    const response= await fetch(`${url} ${id}`,{

    method:"DELETE", 
    headers: {
       'Content-type': 'application/json' //Tells the server the data being posted is a JSON data 
     },
    })

   return response

}

deleteRequest('http://your_backend_url/api/v1/delete/',"2")
.then(response => response.json())
.then(data => console.log(data))// to use the data receieved
.catch((error)=> console.log(error))

How to Send HTTP Requests in Javascript.

There are several ways to send HTTP Requests, In this section, you'll learn the two major ways to create and send an HTTP request in Javascript, they are;

  • Fetch API

  • Axios

Fetch API

This is the most common and one of the easiest way to send HTTP requests in javascript. The modern Javascript engine ships with this API already built in so you do not need to install it. The Fetch API should seem familiar to developers who are already used to sending HTTP requests using XMLHttpRequest; this is simply a faster and more powerful version of it.

The Fetch API can be called using the fetch() syntax, it takes two arguments which are:

  1. A URL which is a Javascript string and a path to the data needed.

  2. An Object containing: methods, Headers and other instructions needed.

The second argument -The Object- is optional when using the GET method, but often compulsory when using other methods, especially when uploading data from to server. The Object contains several key-value pairs, the important ones are:

  • method: This gets a value of the method you want to use in your request e.g POST, PUT, DELETE etc.

  • headers: This section is very important, especially when sending data to the server, It's value is a javascript object that enables the client to pass several additional information into the HTTP request; information such as Content-Type, CORS, Caching, Auth, Conditionals etc.

  • body: The value of this Key is the payload(data) you're posting to the server, it is important to know that the data type in the Header section above must match the data type of your payload. The most common data type used in javascript is the JSON data type (you can convert your regular Javascript Object to JSON data using JSON.stringify(data) )

USING THE Fetch API

  • The code snippet below showing step by step way of POSTing formData using the Fetch API
//create a form data
let formData = new FormData();
    formData.append("name", "Javascript");
    formData.append("password", "Javascript123");

// Call the Fetch API and add it's parameters
fetch('http://your_backend_url/api/v1/upload',{

   method:"POST",
   headers:{
           "Content-Type": "application/x-www-form-urlencoded" //for form Data
         }
   body: formData// for JSON Data use JSON.stringify(data)

})
.then((response)=> response.json())
.then((data)=> console.log(data))//do something with the data e.g show a success message
.catch((error)=>console.log(error))
  • Code snippet showing a simple GET Request using the fetch API
fetch("myproducts.com/productList")
.then((response)=> response.json())
.then((data)=>  console.log(data)  )//do something with the e.g display products
.catch((error)=>console.log(error))
  • Code snippet showing the combination of a POST and GET request. In this example data was fetched from one host server and posted to another host server
fetch("https://your_backend_server/v1/products/productList")
.then((response)=> response.json())
.then((data)=>  
  //recieve the data and then send to another host server
   async function sendData(myData){

     const response= await fetch('http://your_backend_url/api/v1/upload',{
           method: "POST"// or PUT,
           headers: {
                  "Content-Type": "application/json",
                },
            body: JSON.stringify(myData),
         })

     return response

}
  sendData(data)
  .then((response)=> response.json())
  .then((data)=> console.log(data))
  .catch((error)=> console.log("error message:"+ error))

 )//do something with the e.g display products
.catch((error)=>console.log(error))

The fetch API is a really fast and powerful tool to send HTTP requests in modern Javascript, even more, important is it compatible with almost all browsers with a compatibility score of 92!

Axios API

Ever since it was introduced in 2016, Axios API has remained one of the most powerful tools to send HTTP requests. It is a third-party package used to send to send HTTP requests in javascipt and nodeJS, Axios is similar to the traditional XMLHttpRequests like the Fetch API also like the Fetch API, the Axios API requires two parameters- A URL and a javascript object, As in the Fetch API, the Object is also mandatory for GET Requests- but unlike the Fetch API that ships with modern Javascript it needs to be installed into your program

Installing The Axios API.

There are several ways to install the Axios API in your program, the most common and efficient way is by using the Node Package Manager(npm)

// open the terminal in your code editior and install using:

$ npm install axios

To Import The Axios API Into Your Script.

//At the tope of your Javascript file, import the Axios library using
const axios = require('axios').default;
//this will allow axios methods and parameters to be autocompleted while typing

After importing you get access to all the Axios HTTP methods like GET, POST, DELETE etc, and that's it, you can now begin to use the Axios library in your Javascript file. Below are some code snippets to illustrate the usage of Axios API.

  • Sending GET Requests.
const axios = require('axios').default;

async function getUser(id) {

    const response = await axios.get(`url/user?ID=${id}`)

    return response

}
getUser(1234)
.then((response)=> console.log(response.data))
.catch((error)=>console.log(error))

Notice how the usual response.json was omitted in the then block? this is because the Axios API automaically resolves JSON data and returns a javascript object instead. This response object contains several keys like status, data, config, header

  • An Alternative way to use the GET method on Axios.
const axios = require('axios').default


async function makeRequest() {

    const config = {
        method: 'get',
        url: 'http://webcode.me'
    }

    let response = await axios(config)

    console.log(response.data);
}

makeRequest();//can be called using an onSubmit event listener

Sending an HTTP Request to get the number of followers of a GitHub user.

const axios = require('axios').default

async function getNumberOfFollowers(userName) {

  let response = await axios.get('https://api.github.com/users/${githubUserName}')

  let nOfFollowers = response.data.followers
  let location = response.data.location

  console.log(`# of followers: ${nOfFollowers}`)
  console.log(`Location: ${location}`)
}

getNumberOfFollowers("janbodner")
  • A Simple POST Request Using Axios to send a Form Data.
const axios = require('axios').default

let formData = new FormData();
    formData.append("firstName", "John")
    formData.append("lastName", "Doe")

async function makeRequest() {

    const config = {
        method: 'post',
        url: 'https://httpbin.org/post',
        headers: {
         'Content-Type': 'application/x-www-form-urlencoded',
        }
        data: formData,


    }

    let response = await axios(config)

    console.log(response.status)// gives the status of the request, you can   display a success message if successful 
}

makeRequest()

The Axios library provides a couple of shorthands that can be used when sending a request, some of them are listed below, feel free to play around with them.

  • axios.request(configObj)

  • axios.get(url, configObj)

  • axios.delete(url, configObj)

  • axios.head(url, configObj)

  • axios.post(url, data, configObj)

  • axios.put(url, data, configObj)

  • axios.patch(url, data, configObj)

The Axios API also provides an all method that resolves multiple HTTP requests, an example is given in the code snippet below.

const axios = require('axios').default

axios.all([
  axios.get('https://api.github.com/users/janeDoe'),
  axios.get('https://api.github.com/users/johnDoe')
])
.then((responseArr)=>{
  console.log('user1 is located at: ', responseArr[0].data.location)
  console.log('user2 is located at: ', responseArr[1].data.location)
})
.catch((error)=> console.log(error))

In the above example, the all method was used to make two HTTP request simultaneously, the Axios API resolves the promises and then returns an array that contains the responses, you can then iterate the array to access your data. It is important to note that If one of the requests you’re sending fails, the code will break and an error will be thrown.

Another cool thing the Axios API can do is monitor the Progress of POST requests, you know the way you see a progress bar while uploading your media on Facebook, Instagram, Twitter and all the other social media platforms, well that is quite easy to create with Axios. An Illustration is given in the code snippet below:

  • First, create an HTML form
<!-- Form -->
<form id="form">
    <input type="file" accept=".png, .jpg" id="file">
    <button type="submit">Upload file!</button>
</form>
  • Next, create a Progress bar using an HTML div

<div>
    <label for="progress-bar">0%</label>
    <progress id="progress-bar" value="0" max="100"></progress>
</div>
  • Next, Handle Form submission with a submit event listener in your index.js file.
const axios = require('axios').default

//traverse the DOM to get and store the Form and Progress bar elements
const form = document.getElementById('form');
const bar = document.getElementById('progress-bar');

//Set up an event listener to handle submission
form.addEventListener('submit', function(e) {
  e.preventDefault();// to prevent the default submit behaviour
  const formData = new FormData();
  const file = document.getElementById('file');
  const img = file.files[0];
  formData.append('image', img);

  // POST request to be added here
})
  • Next, Handle the POST Request using Axios and Progress Tracking.
const axios = require('axios').default


const form = document.getElementById('form');
const bar = document.getElementById('progress-bar');


form.addEventListener('submit', function(e) {
  e.preventDefault();
  const formData = new FormData();
  const file = document.getElementById('file');
  const img = file.files[0];
  formData.append('image', img);


// Axios POST request Config Object
const config = {
    onUploadProgress: function(progressEvent) {
    const percentCompleted = Math.round((progressEvent.loaded / progressEvent.total)*100);
    bar.setAttribute('value', percentCompleted);
    bar.previousElementSibling.textContent = `${percentCompleted}%`
    if (percentCompleted === 100) {
      bar.previousElementSibling.textContent = `Upload complete!`
    }
  }
}


axios.post('https://httpbin.org/post', formData, config)
  .then(res => console.log(res))
  .catch(err => console.log(err))


})

In the Axios config object above, the onUploadProgress key has been used to set up the progress tracking functionality, this key takes a function as its value. This function receives a progressEvent object as an argument from the Axios API, the progressEvent object contains information about the file being uploaded i.e the total size of the file and the amount that has been loaded already, using these you can get the percentage completed which can be used to track the file's progress and update on the DOM. It's that simple!

As a side note, the Axios API is also supported by most browsers even older versions of Internet Explorer.


Error Handling.

It is important to know that not every HTTP Request sent to a server returns a success status. There are several reasons why an HTTP Request may fail or return an Error status, It could be a result of Server errors, Network Failure, Expired API keys, Broken links etc. Because of this, it is important to handle HTTP Request Errors in your program; One very easy way to handle this is by coupling our Promises with the catch block.

In Javascript, the catch block sets an Error boundary to catch the error messages in programs and then running an alternative piece of code. An example of this is given in the code snippet

function sendHttpRequest(){
//send Http request here
}

sendHttpRequest()
  .then((response) => doSomethingElse(response))
  .catch((error)=> console.log(error));

In the code snippet above the catch block is used to catch and handle error responses that may occur due to a failed HTTP request.

It is important to mention here that the catch block may not catch all failed HTTP Requests especially while using the Fetch API, for example, the catch block does not catch failed requests that are due to Network error in Fetch API. For this, another method of Error Handling shown in the code block below is used.

function doSomething(){
//send an HTTP request
}

doSomething()
  .then((response) => {

     if(response.status<300){
       console.log("Success")
     }else{

       console.log("error")

})
  .catch(failureCallback);

The response to an HTTP Request is a javascript object that contains several keys such as body status error etc, In the code snippet above an if/else statement was used to create an error boundary by checking the value of the status key of the response object. All response status below 300 is considered successful, In the Illustration above, the if block was used to check the response status, If less than 300(successful) a success message is shown to the user else an error message is displayed. Also used in the illustration is a catch block to handle errors that are not network related.

You typically want to set an error boundary that is robust enough to catch all forms of errors, this may involve the use of several error detection methods. Below is another illustration that combines the try/catch, async/await and status checking methods

async function getHttpData(){
  try{

     const response=await 
     fetch("https://jsonplaceholder.typicode.com/posts/products")

     if(response.status<300){
       console.log(response.json())
    }else{
       console.log(`Network error ${response.status}`)
   }

  }catch(error){

    console.log(error)

  }
}
getHttpData()

In the above example, the function getHttpData was created using the async keyword, the HTTP Request code in it was then wrapped in a try/catch block to serve as an error boundary, the if/else statement was also used for a similar reason.


Fetch API or Axios?

Both the Fetch and Axios APIs have great browser compatibility, they are both easy to use and similar in several ways. However they have subtle differences, in this section, you'll learn about these differences to help you make a better choice for your projects.

  1. Security: The Axios API is built with Cross-Site Request Forgery(CSRF) Protection, which helps to protect users against malicious and phishing links. Take for example, you are logged into your bank’s webpage where you generate an OTP or a Token to make a transaction, just about the same time you received and clicked on a malicious link from a scammer; without the CSRF Protection, the scammer may gain access to your bank details and even funds through CSRF. The Fetch API does not ship with this protection. Although modern websites have evolved and become protected against such attacks, the little extra layer of protection provided by Axios is still quite handy.

  2. Payload Data In POST Request: The Axios API automatically converts the payload to a JSON type when sending an HTTP request, this can, of course, be overridden. When using the Fetch API though, you need to manually convert your Javascript object to a JSON type using JSON.stringify as you’ve seen several times in the code snippets above

  3. Error Handling: The Axios API is by far better when it comes to effective and seamless error handling. Instead of checking for the status code to handle errors as you’ve seen thus far when we used the Fetch API, the Axios API has been automated to check and throw errors for status codes above the 2XXs. Quite lovely, right?

  4. Third Party: While the Fetch API is built into modern browsers and therefore does not need to be installed, the Axios library is a third-party library that needs to be installed every time. There have been debates as regards the need for a third-party API, especially with the extra risk of unwanted data exposure that comes with it, and since the Fetch API is perfectly capable of reproducing the key features of the Axios API (with some extra bit of work, of course) some developers tend to choose the built-in Fetch API. Nevertheless, the Axios API remains popular among developers gathering about 42 million weekly downloads!

  5. Browser Compatibility: One of the major advantages of the Axios API is its robust browser compatibility. Unlike the fetch API, it is compatible with older versions of Internet Explorer, hence it has better browser compatibility than the Fetch API. Although this can be solved using Polyfill, it is still an advantage to Axios.

  6. Multiple Requests: With the Axios library, It is possible to send multiple requests to similar or different host servers at the same time using the all method available on the axios Object. An illustration of this has been given in the Axios API section of this article.

  7. Progress Tracking: With the Axios library, It is also possible and easy to track the upload progress in POST requests. An illustration of this has also been given in the Axios API section of this article.

In the end, the Fetch and Axios APIs are both very powerful and similar tools for sending HTTP requests. Although the Axios API has a couple of advantages over the Fetch API, these features can also be implemented using the Fetch API, though less easily. The use of either of the two is subject to personal preferences and project requirements.


Conclusion.

In this article, you learned what an HTTP request is, How to create and send them, How to Handle errors Involving them and Several powerful tools that can help create better and more efficient HTTP requests. To learn more about how these tools work behind the scenes, click the following links: Fetch API and Axios API Documentation. You can also read more about Promises and asynchronous programming here.

I hope you had a great time reading this, kindly like the post and drop your reviews below. Until next time, folks!