DEV Community

Cover image for HTTP Requests in JavaScript
Dawit
Dawit

Posted on • Originally published at oneminch.dev

HTTP Requests in JavaScript

Making requests is the heart of the Internet. Whenever you are browsing the internet, all what you are doing is requesting information from servers, which are basically interconnected computers. It's the foundation of how websites work. A simple case is a person typing "www.duckduckgo.com" and getting the DuckDuckGo search page. A request is made to a web server, which then sends back the files for that page, which will be rendered in the browser as a web page. This is made possible by a protocol known as HTTP (HyperText Transfer Protocol). On MDN web docs, the HTTP protocol is described as:

HTTP is a protocol which allows the fetching of resources, such as HTML documents. It is the foundation of any data exchange on the Web, and it is a client-server protocol, which means requests are initiated by the recipient, usually the Web browser. A complete document is reconstructed from the different sub-documents fetched, for instance text, layout description, images, videos, scripts, and more.

Requesting a resource from the client side uses this HTTP protocol, and these types of requests are known as HTTP requests. These requests are essential for any type of online activity performed on the web.

JavaScript has a set of great tools and methods that allow us to make HTTP requests to send or receive data from a certain server or endpoint. A couple of commonly used ways to make requests are XMLHttpRequest and Fetch.

1. XMLHttpRequest (XHR)

AJAX stands for Asynchronous JavaScript And XML. Requests made are asynchronous, which means they don't interrupt the execution of other JavaScript code. In other words, JavaScript code besides the AJAX code doesn't have to wait for requests to finish being executed. It can execute simultaneously. The method that makes this possible is the XMLHttpRequest(). Despite the prefix 'XML', we can process any form of data for our requests.

The XMLHttpRequest() method works as a constructor for us to create an instance and call our AJAX requests on.

const xhr = new XMLHttpRequest();
Enter fullscreen mode Exit fullscreen mode

Our xhr object has a number of methods and properties that allow us to make different types of requests.

Methods

xhr.open()

We can then use the open() method on our xhr object to initialize or configure a request. This method takes the following parameters:

  1. Method: GET, POST, PUT or DELETE,
  2. URL: Path to our resource,
  3. Async: Boolean value (true or false); Optional & default value is true,
  4. Username & Password — Optional; Credentials if authentication is needed.

It follows the syntax:

xhr.open(Method, URL[, Async]);
Enter fullscreen mode Exit fullscreen mode

xhr.send()

This method allows us to open and send our request. It takes an optional parameter that contains our request body, which is useful when making POST requests.

xhr.send([body]);
Enter fullscreen mode Exit fullscreen mode

xhr.setRequestHeader()

This method is used to set HTTP headers for our request, such as Content-Type & Accept. Similarly, we can use xhr.getResponseHeader() to get header values from our response.

// Set header for request
xhr.setRequestHeader("Content-Type", "application/json");

// Get header for response
xhr.getResponseHeader("Content-Type");
Enter fullscreen mode Exit fullscreen mode

xhr.abort()

This method is useful when we want to cancel a request. Imagine a scenario where a user wants to cancel a request because it's taking too long. xhr.abort() can be used to stop the request.

xhr.abort();
Enter fullscreen mode Exit fullscreen mode

Properties

xhr.response

This value contains the response body we receive from our request. xhr.responseText is also a similar property, which is used if our response is in a string format.

const res = xhr.response;
Enter fullscreen mode Exit fullscreen mode

xhr.responseType

This is used to set the response type for our xhr object. It can be in any one of these formats:

  • text/"" - default value
  • json
  • document
  • blob
xhr.responseType = "json";
Enter fullscreen mode Exit fullscreen mode

xhr.readyState

Our request changes states as it progresses, and the current state of our request can be accessed by this property. Its values range from 0 (initial state) to 4 (completed state). The event onreadystatechange can be used to detect whenever there is a change in state.

xhr.onreadystatechange = function () {
  if (xhr.readyState == 1) {
    /* request opened */
  }
  if (xhr.readyState == 2) {
    /* headers received */
  }
  if (xhr.readyState == 3) {
    /* response loading */
  }
  if (xhr.readyState == 4) {
    /* request complete */
  }
};
Enter fullscreen mode Exit fullscreen mode

Events

xhr.onload

This event is fired when our request is successful and the result is sent back. This can also be computed with xhr.onreadystatechange when xhr.readyState is 4.

xhr.onload = () => {
  // Code to run when results are ready
};
Enter fullscreen mode Exit fullscreen mode

xhr.onerror

This event is invoked when there is an error in our request, which could be due to network error or invalid configuration of our request.

xhr.onerror = () => {
  // Code to run when request has failed
};
Enter fullscreen mode Exit fullscreen mode

xhr.onprogress

This event is called repeatedly while our request is processed. It can be used to figure out the loading progress of a download or even a page load to let the user know how far along their request has been processed. An event parameter can be passed to xhr.onprogress and it has properties event.loaded and event.total, which can be used to show the actual progress feedback.

xhr.onprogress = (event) => {
  // Code to run while request is being processed
  console.log(`Loaded ${event.loaded} of ${event.total}`);
};
Enter fullscreen mode Exit fullscreen mode

Example

We are going to use a simple fake online REST API called JSONPlaceholder to make example requests. We will use it to request and submit fake posts. According to the documentation for JSONPlaceholder, our path to the resource we want is https://jsonplaceholder.typicode.com/<endpoint>, and there are several endpoints to choose from. For this demo, we'll use 'posts' as our endpoint. For this certain endpoint, we are going to receive and submit to an array of posts which are enclosed in objects. We also want our request to be asynchronous.

Method: GET - is used to retrieve data.

// Our path to the resource
let reqURL = "https://jsonplaceholder.typicode.com/posts";

// 1. CREATE OUR XHR OBJECT
const xhr = new XMLHttpRequest();

// 2. SET OUR RESPONSE TYPE
xhr.responseType = "json";

// 3. CONFIGURE OUR REQUEST
xhr.open("GET", reqURL, true);

// 4. SEND THE REQUEST
xhr.send();

// 5. DECLARE FUNCTIONS BASED ON EVENTS
xhr.onload = () => {
  const data = xhr.response;
  console.log(data);
};

xhr.onprogress = (event) => {
  console.log(`Loaded ${event.loaded} of ${event.total}`);
};

xhr.onerror = () => {
  console.log("Request failed!");
};
Enter fullscreen mode Exit fullscreen mode

As an output, we get a list of objects in the form of an array.

// An example object from the array we get
{
    id: 1,
    title: "sunt aut facere repellat provident occaecati excepturi",
    body: "quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit ...",
    userId: 1
}
Enter fullscreen mode Exit fullscreen mode

Method: POST - is used to send new or updated data to the specified resource.

// Our path to the resource
let reqUrl = "https://jsonplaceholder.typicode.com/posts";

// 1. CREATE OUR XHR OBJECT
const xhr = new XMLHttpRequest();

// 2. Configure a `POST` request
xhr.open("POST", reqUrl);

// 3. Create a JSON 'post' object
const json_data = {
  title: "this is title",
  body: "this is body",
  userId: 1
};

// 4. Set the `Content-Type` header
xhr.setRequestHeader("Content-Type", "application/json");

// 5. Pass a string form of our
//    json_data object to `send()`
xhr.send(JSON.stringify(json_data));

// 6. DECLARE FUNCTIONS BASED ON EVENTS
xhr.onload = () => {
  const data = xhr.response;
  console.log(data);
};

xhr.onprogress = (event) => {
  console.log(`Uploaded ${event.loaded} of ${event.total}`);
};

xhr.onerror = () => {
  console.log("Request failed!");
};
Enter fullscreen mode Exit fullscreen mode

Other than the couple of steps we have added, the general structure and process of making HTTP requests is very similar and perhaps even almost identical.

For our demo API, the object we 'posted' is not actually added to their database of posts. Since it is a fake API, the process is also faked, as the purpose of this code and the API is to demonstrate how requests work and to test code.

Method: PUT - is used to update or modify data at the specified path. This is almost identical to our POST method process. The only things that change are the path, the method name and the object we are updating. Other than these values, the rest is the same.

// 1. Our path to the object we want to update
//    Notice the '/1' added to the end
let reqUrl = "https://jsonplaceholder.typicode.com/posts/1";

// Configure a `PUT` request
xhr.open('PUT', reqUrl);

// Create a JSON 'post' object
// We added 'id' so it can be used to
// update the entry with the specified id
const json_data = {
    id: 1
    title: 'this is updated title',
    body: 'this is updated body',
    userId: 1
};
Enter fullscreen mode Exit fullscreen mode

Method: DELETE - is used to delete the specified resource. Based on the documentation for the API, we use a different path to our resource to target and delete an entry.

// 1. Our path to the object we want to delete
//    Notice the '/1' added to the end
let reqUrl = "https://jsonplaceholder.typicode.com/posts/1";

// 2. CREATE OUR XHR OBJECT
const xhr = new XMLHttpRequest();

// 3. Configure a `DELETE` request
xhr.open("DELETE", reqUrl);

// 4. SEND THE REQUEST
xhr.send();
Enter fullscreen mode Exit fullscreen mode

For real APIs, we can continue to create another GET request to verify that the data we wanted to delete is actually deleted. We can retrieve all the data and see if the object we sent a DELETE request on is in the database. If it's not, then the data is deleted.

2. Fetch

Fetch is a promise-based web API. It is a modern alternative to XHR. I have explained in detail how the fetch() API works here. But let's redo the previous requests using fetch and see the difference.

Method: GET

let reqUrl = "https://jsonplaceholder.typicode.com/posts";

fetch(reqUrl)
  .then((res) => res.json())
  .then((data) => console.log(data))
  .catch((error) => console.log(error));
Enter fullscreen mode Exit fullscreen mode

Method: POST

fetch(reqUrl, {
  method: "POST",
  body: JSON.stringify({
    title: "this is title",
    body: "this is body",
    userId: 1
  }),
  headers: {
    "Content-type": "application/json"
  }
})
  .then((res) => res.json())
  .then((data) => console.log(data))
  .catch((error) => console.log(error));
Enter fullscreen mode Exit fullscreen mode

Method: PUT

// Our path to the object we want to update
let reqUrl = "https://jsonplaceholder.typicode.com/posts/1";

fetch(reqUrl, {
  method: "PUT",
  body: JSON.stringify({
    id: 1,
    title: "this is title",
    body: "this is body",
    userId: 1
  }),
  headers: {
    "Content-type": "application/json"
  }
})
  .then((res) => res.json())
  .then((data) => console.log(data))
  .catch((error) => console.log(error));
Enter fullscreen mode Exit fullscreen mode

Method: DELETE

// 1. Our path to the object we want to delete
let reqUrl = "https://jsonplaceholder.typicode.com/posts/1";

fetch(reqUrl, {
  method: "DELETE"
});
Enter fullscreen mode Exit fullscreen mode

Fetch is a much cleaner and simpler way of doing what XHR allows us to do. Tracking progress is not yet supported in fetch. Due to that and many other reasons like browser support, XHR is still an important part of making requests.

There are also third-party tools such as axios and jQuery's $.ajax(). These utilize XHR and/or Fetch API under the hood to provide a much cleaner way of making requests for developers.

Read More

Top comments (2)

Collapse
 
eteimz profile image
Youdiowei Eteimorde

Your article makes XmlHttpRequest less scary 😄

Collapse
 
oneminch profile image
Dawit

I'm glad it does 😄