Learn How to Make HTTP Requests With XMLHttpRequest, fetch() and async & await10 min read
Fetching and manipulating data through HTTP requests is an indispensable part of the Web-development. You might want to get the data through HTTP requests for a host of reasons, for example, get some data from the API, update or delete data via HTTP requests. When you click to a submit button, what happens under the hood, where does the information go, and how it is processed? The answer is all about the HTTP requests. There are many HTTP methods that we can use to work with data. However, in this article, we are going to learn the 2 most common HTTP requests which are GET and POST requests.
First, we need a basic understanding of how HTTP works over the internet, check out this article if you want. Since we mostly use the HTTP requests to manipulate the data from the API, then having a fundamental knowledge of REST principles is also great.
Table of Contents
GET and POST Methods
GET – The GET method requests a representation of the specified resource. Requests using GET should only retrieve data and should have no other effect.
POST – The POST method is used to submit some data to a specific resource, often cause a change in state or side effect on the server-side. The submitted data usually lies in the body of the POST method.
REST principles
Before we jump into how to create some GET and POST requests in JavaScript, let’s briefly have a look at the REST principles. Representational State Transfer (REST) is a software architectural style that defines a set of constraints to be used for creating web services. The important fact about REST is it works over HTTP. Resources is the main concept of REST, and the resource here is defined by URLs. Each HTTP method defines a verb to work with this resource.
For example, Spotify API is based on a simple REST principle. https://api.spotify.com is a based URL that defines some resources such as releases, features, and music categories available on Spotify. An HTTP method like GET lets you get the data from this URL, such as a new release.
- https://api.spotify.com/v1/browse/new-releases — with GET should return the new song and albums released on Spotify.
- https://api.spotify.com/v1/browse/new-releases — with POST will create a new resource over https://api.spotify.com/v1/browse/new-releases.
Making HTTP requests in JavaScript is simple. There are a huge number of serviceable methods and modules readily in JavaScript which let us send or retrieve some data from a resource on the internet and put you at ease.
GET and POST Requests with AJAX
Asynchronous JavaScript and XML (AJAX) enables web applications to send and retrieve data from a server asynchronously. The XMLHttpRequest
object is a key factor of AJAX, this object lets you send and retrieve XML data and other formats such as JSON from a server without refreshing the page.
Now let’s construct a typical GET request in JavaScript with XMLHttpRequest
object:
// XMLHttpRequest GET
const xhr = new XMLHttpRequest();
const url = "http://example.com/endpoint";
xhr.responseType = 'json';
xhr.onreadystatechange = () => {
if(xhr.readyState === XMLHttpRequest.DONE){
// Code to execute with response
}
}
xhr.open('GET', url);
xhr.send();
Let’s break down what’s happening here:
- First, I create an
XMLHttpRequest
with a new keyword, you can name this object whatever you want, but it’s common practice to name variable asxhr
. - On the next line, we store the
url
which will receive a GET request. - A
XMLHttpRequest
has a property namedresponseType
which is how the response type is formatted. In the sixth line, the JSON format will be represented as a response type of ourxhr
object. onreadystatechange
is an event handler which is called when the ready state of thexhr
object changed.- Inside this event handler, the
readyState
property returns the state an XMLHttpRequest client is in, if it equalsXMLHttpRequest.DONE
which means the request has finished. - Right underneath this event handler, we call the
open
method on this object. Thisopen
method accepts two parameters, the request type, GET, and the specified URL to send the request to. - Finally, we send the request to the server with the
send
method.
Let’s move on the POST request with an XMLHttpRequest
object:
const xhr = new XMLHttpRequest();
const url = "http://example.com/endpoint";
const data = "Some data";
xhr.responseType = 'json';
xhr.onreadystatechange = () => {
if(xhr.readyState === XMLHttpRequest.DONE){
// Code to execute with response
}
}
xhr.open('POST', url);
xhr.send(data);
As we can easily notice, the POST request looks pretty much the same as the GET request. There is a slight difference though, the GET request only lets us retrieve some data from a server and has no side-effect. The POST method will have some data come along when we send the request to the server.
On line third, we define a variable named data
which stores some data. On line eleventh, we use the open
method to initialize a new request, pass in to this method the ‘POST’ value as the first parameter and the URL. At the end of this code fragment, we send the data
to the server.
Why have we passed an argument to xhr.send()
with a POST request? This data
we pass in will be posted to a resource and this resource will process the data
and send the data
back after the process. For example, when you enter an URL to a shorten URL website and click the “Submit” button, actually you’ve created a POST request. The data is sent to the server here is the URL you typed in and the server will process this POST request and give you back the shorten URL.
GET and POST Request with fetch()
An alternative way that you can use to make HTTP requests on the Web browser is the Fetch API. The Fetch API is a new and modern interface that allows you to make HTTP requests in the web browsers. The fetch()
method from the Fetch API can perform all tasks of an XMLHttpRequest
objects. By using fetch()
, we can send an AJAX request or network request to a server and get the JSON response. Since the fetch()
method returns a promise, your code can look more readable and callback hell is avoidable.
Basic Syntax
fetch(url,[options])
The fetch()
function takes 2 parameters, the first one will be the url
we want to send and retrieve data. The second one is optional, which can be a method, header, etc…
Let’s create a GET request with the fetch()
function:
fetch("http://example.com/endpoint")
.then(response => {
if (response.ok) {
return response.json();
}
}
)
.then(jsonResponse => {
return jsonResponse;
}).catch(networkError => {
console.log(networkError.message);
});
How the fetch
function works:
- First, we pass an URL which is the resource we want to work with as the first parameter of the
fetch
method. - After that, this method returns a promise, when the request is completed which means this resource is available, this promise is resolved with a
Response
object. - We pass this
Response
object as an argument of the then method asresponse
. - This
Response
object has a number of handy properties, some of them areok
and.json()
, thisresponse.ok
will returntrue
if the response returned successfully (the status code from 200-299). - If it is
true
, we use the.json()
method to convert the response data to the JSON format and return this format. - This
response.json()
method also returns a promise, that why we can chain anotherthen
method once again, inside the second then, we just simply return the data in JSON formatjsonResponse
. - If there is any error occurs in the first promise or the second one, then we can use the
catch
method to handle thereject
state of the promise which causes an error.
As we can observe, with the fetch()
method, our code now looks more concise and readable compared to thenXMLHttpRequest
version. There is no open()
or send()
methods, just simple and versatile promises.
Now let’s learn how to create a POST request with fetch()
method:
fetch("http://example.com/endpoint", {
method: 'POST',
body: 'Some cool data'
}).then(response => {
if(response.ok){
return response.json();
}
}).then(jsonResponse => jsonResponse)
.catch(error => console.log(error));
To make a POST request to the server, we pass the second argument to the fetch
method, this object we passed in determine the information we want to send the the server. This object has 2 properties, method
defines the type of HTTP request and body
is the data we want to send. Henceforth, every thing is identical to the GET version we have done. The body of each method can contain arbitrary code, here I just simple return an objects in each method for simplicity.
The fetch() method and async & await
Because the fetch()
method returns a promise, and this promise has to be resolved before we want to do any further actions, in harmony with this rhythm, the concept of async
and await
function comes in handy.
The async
function returns a promise, and the await
keyword only exists inside the async
function. Basically, the await
keyword is placed right before a promise. It will halt the execution of the program until the promise is resolved! There would be no point of we haven’t obtained a resolved promise and doing some actions at the same time. With async
and await
keyword, callback hell is totally avoidable.
Let’s construct a sample GET request with fetch()
, async
and await
:
const getData = async () => {
try{
const response = await fetch("http://example.com/endpoint");
if(response.ok){
const jsonResponse = await response.json();
return jsonResponse;
}
}catch(error){
console.log(error);
}
}
How it works:
- We create a function
getData()
, this will be called when we want to get some data fromhttp://example.com/endpoint
. - The code in the
try
block will send a request and handle the response. Thecatch
statement will then take care of an error if it is thrown. - Inside the
try
block, thefetch()
method returns a promise, theawait
keyword placed right before to beckon that this promise need to be resolved before move on the next lines and we save this promise toresponse
. - If the request successfully finished, inside the
if
statement, we have another variable namedjsonResponse
,response.json()
also returns a promise, so again we use theawait
keyword to make sure this promise is resolved before moving on. - Then at the end of the
if
statement, we return the formatted JSON response. - If there is any error occurs in the
try
block, thecatch
block will log the errors.
What about the POST request with fetch()
, async
and await
:
const postData = async () => {
try{
const response = await fetch('http://example.com/endpoint', {
method: 'POST',
body: 'some cool data'
});
if(response.ok){
const jsonResponse = await response.json();
return jsonResponse;
}
}catch(error){
console.log(error);
}
}
To make a POST request, we use the second argument to send the data to the server, then we can do exactly the same as we did with the GET request.
Summary
In this article, we have learned some of the most common ways to make HTTP requests in JavaScript. The XMLHttpRequest
is the old and traditional way to make HTTP requests, fetch()
is a modern one which returns a promise. A GET method will retrieve the data and have no other effects, the POST method usually contains some data in the body to send to the server.