Using AJAX and JSON in JavaScript

John Au-Yeung
Oct 29, 2019 · 10 min read
Image for post
Image for post
Photo by NASA on Unsplash

AJAX makes our page dynamic and lets us refresh data in our web pages without refreshing the page. It makes user pages interactive and creates a slicker user experience for the user. AJAX stands for Asynchronous JavaScript and XML. It’s used to describe the way that we use the XMLHttpRequest object to refresh part of the page by getting data from the server via HTTP requests and manipulate the DOM to refresh the data.

The HTML DOM changes the dynamically. AJAX allows us to use the XMLHttpRequest object to get data from the server and manipulate the DOM without blocking the execution of other parts of the JavaScript program. Despite that AJAX stands for Asynchronous JavaScript and XML, JSON is frequently used for sending and retrieving data from the server. JSON stands for JavaScript Object Notation. JSON is a data format that very close to a JavaScript object, except that it can’t contain any functions or dynamic code. Only string, numbers, arrays and objects without functions are allowed.

Old style web pages refresh the whole page to refresh the data. This is getting less and less common today as it creates a less pleasant experience than just refreshing parts of the page that’s needed to refresh. Refreshing the whole page would make the whole page flash and everything has to be loaded again.

AJAX is also great for updating live data on a page since it only refreshes parts of a page that’s need to refresh. It’s good for tables, charts, emails, and things that refresh periodically.

To view AJAX in action, we can look at the browser’s development console. For example, in Chrome, we can go to a website like weather.com and then we can press F12 or right click the browser window and click Inspect to open the development console. Then we can go to the Network tab. In there, we have the XHR button, XHR stands for XmlHttpRequest, which is what’s originally used for AJAX. On the left side of the XHR section, click on one of the entries. Next click on Preview, and then we can see something like the following:

Image for post
Image for post

This is the JSON data that’s parsed by the browser and can be inserted to the DOM of a web page. All AJAX is sending data via HTTP requests and then response will be obtained from the the server, then the data is populated on the page via manipulating the DOM. Most modern browsers work the same way and support AJAX.

Same-Origin Policy

In most cases, requests are made to a server that has a different domain from the server that has a different domain from the originating server. If we do that without setting some options, we will get an error since most browsers by default stop cross origin requests from being made without setting specific options on the server and the client. The purpose of this is to prevent browsers from downloading code that’s unknown to the browser. This policy applies everywhere, even on our local computer, since it’s can be used to compromise the security of our computers no matter where the data is downloaded from.

To allow requests to request between computers with different domains from a web browser. The server has to enable Cross-Origin Resource Sharing, or CORS for short. This has to be enabled on the server side. If we look at a cross origin HTTP request, we should see an OPTIONS request before the actual request is made and in we should see the following in the response headers:

Access-Control-Allow-Origin: *

Alternatively, we can put the client and server side code in the same domain. This wouldn’t violate the same origin policy in browsers since the request from the browser is made from the same domain from the server.

Using the XMLHttpRequest Object

We can use the XMLHttpRequest object to make a request to a server and retrieve its response. This can be done with a simple example. In this example, we will load content from a text file and then put the content inside a page. Create a file called index.html and add:

<html>
<head>
<title>XMLHttpRequest</title>
</head>
<body>
<h1>XML HTTP Request</h1>
<button id="load">Load Data</button>
<div id="content"></div>
<script src="script.js"></script>
</body>
</html>

The create a file called script.js and add:

const reqListener = response => {
const content = document.getElementById("content");
content.innerHTML = response.currentTarget.response;
};
const loadData = () => {
const req = new XMLHttpRequest();
req.onload = reqListener;
req.open("get", "file.txt", true);
req.send();
};
window.onload = () => {
const loadButton = document.getElementById("load");
loadButton.onclick = loadData;
};

Then in file.txt we put:

Hello world.

In the above example, we created an instance of the XMLHttpRequest object to make a GET request to our server, which is a local web server that servers the file.txt file. We call the open function to start the request, The first argument is the HTTP request method, which can be get , post , put , patch or delete . The second argument is the URL or relative path to your server side resource. The third argument is for setting whether the HTTP request happens asynchronously. Usually, it should be true since we do not want to hold up other parts of our JavaScript code from loading. Also, we set the req.onload listener function to get the response from the server and then populate the result. In reqListener function, we get the response from the server when it’s available and then populate the content of the element with ID content with it. This happens after we call end send function on the req object.

Once we have these files we should get ‘Hello world’ when we click ‘Load Data’, we should get ‘Hello world.’ in our page.

Image for post
Image for post

This is the simplest case for making HTTP requests and then getting the result with AJAX. If we want to make requests that are more complex, then this is a very cumbersome way to do it. Fortunately, we have the Fetch API. to make a HTTP requests in our client side applications.

Promises

In JavaScript, a lot of code are asynchronous since it’s single threaded. To prevent holding up a program by code that finishes running in a indeterminate amount of time, we have to make a lot code asynchronous to prevent holding up the rest of the program from executing.

A promise is an object that represents an asynchronous process that finishes in an indeterminate amount of time. Before it’s executed then its status is pending. It can end in 2 states. If it’s successful, then the promise is resolved. A resolved promised is in the fulfilled state. Otherwise, it ends by by rejecting the promise. A promise is rejected if an error occurred. If an error occurred then the value that’s returned in the promise is ignored. In either case, when the promise finishes executing, a promise is in the settled status. That means settled status includes both fulfilled and error status.

The benefit of using promises for writing asynchronous code is that we can chain multiple promises together as if they are synchronous code. However, promises can only return other promises and they cannot return anything else. They are chained with the then function, which takes a callback function which has the resolved value when the promise is fulfilled. When an errors occurred they can be handled with the catch function at the end. To execute code no matter what the result of a promise is, we can chain the finally function to the end of a promise.

To run an array of promises, we can use the Promise.all function, which takes an array of promises.

An example of a promise would be something like:

const getTextPromise = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'file.txt', true);
xhr.onload = (response) => resolve(response.currentTarget.responseText);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});

We wrapped the example we have above inside a promise and we resolve the response text instead of populating it in the DOM directly. To populate it in the DOM, we do:

getTextPromise
.then(responseText =>{
const content = document.getElementById("content");
content.innerHTML = responseText;
})
.catch(error =>{
alert(error.toString());
})
Image for post
Image for post
Photo by Rob Fuller on Unsplash

Make HTTP Requests with the Fetch API

The Fetch API makes use of promises to make asynchronous HTTP requests from the browser to a server. It provides us with an easy to use API for making requests. It lets us create HTTP requests with a Request object, then when the server makes a response, then we get a Response object. We make a request with the fetch method. The fetch method takes one mandatory, which includes all the data for making requests. Once the Response object is returned then we can massage it to get it to the form we want and then populate it in our web pages.

Also, it’s aware of concepts like CORS, so we can make cross origin requests if the server allows by setting some options within the argument of the fetch method. To use the fetch method for making HTTP request, we can do it with an example. If we want to make a form for letting users subscribe to your email list, we can write the following code. Create a file calledindex.html and add:

<html>
<head>
<title>Email List Subscribe Form</title>
</head>
<body>
<h1>Email List Subscribe Form</h1>
<form action="" name="nameForm" id="nameForm" method="post">
<label for="firstName">First Name: </label>
<input type="text" name="firstName" id="firstName" /><br />
<label for="lastName">Last Name: </label>
<input type="text" name="lastName" id="lastName" /><br />
<label for="email">Email: </label>
<input type="text" name="email" id="email" /><br />
<input type="submit" value="Subscribe" />
</form>
<script src="script.js"></script>
</body>
</html>

to add the form. Then create a script.js file in the same folder and add:

const APIURL = "http://localhost:3000";const subscribe = data => {
return fetch(`${APIURL}/subscribers`, {
method: "POST",
mode: "cors",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}).then(response => response.json());
};
window.onload = () => {
const nameForm = document.forms.nameForm;
nameForm.method = "post";
nameForm.target = "_blank";
nameForm.action = "";
nameForm.addEventListener("submit", e => {
e.preventDefault();
const firstName = document.getElementById("firstName").value;
const lastName = document.getElementById("lastName").value;
const email = document.getElementById("email").value;
let errors = [];
if (!firstName) {
errors.push("First name is required.");
}
if (!lastName) {
errors.push("Last name is required.");
}
if (!email) {
errors.push("Email is required.");
}
if (!/[^@]+@[^\.]+\..+/.test(email)) {
errors.push("Email is invalid.");
}
if (errors.length > 0) {
alert(errors.join(" "));
return;
}
subscribe({
firstName,
lastName,
email
}).then(response => {
alert(`${response.firstName} ${response.lastName} has subscribed`);
});
});
};

The subscribe function is where we used the fetch method. In there we pass in the URL of the server we are making the request to as the first argument. In the second argument, we set the method, which the HTTP request method for the request we want to make, which is POST. mode should be CORS since we’re making a cross domain request. We don’t want any request caching so we set cache to no-cache . In headers , we set Content-Type to application/json to make the requests data type send JSON. The body is the request body of the request, which we create a JSON object since we are sending JSON to the server. Finally, we return response.json() , which is a promise with the response if the request is successful sent back from the server and converted to JSON format.

To send something to the URL we point to we have to set up a web server. We first install the json-server package by running npm i json-server. Then, go to our project folder and run:

json-server --watch db.json

In db.json, change the text to:

{
"subscribers": []
}

So we have the subscribers endpoints defined in the requests.js available.

Shorten Promise Code with Async and Await

The code above makes use of several promises. We have one for making the request, and then another one for converting it to JSON. Then finally, we make the alert at the end. With the then function, we make to put callback functions as an argument of all of our then functions. This makes the code long is we have lots of promises. Instead, we can use the async and await syntax to replace the then and its associated callbacks as follows. In script.js , we put:

const APIURL = "http://localhost:3000";const subscribe = async data => {
const response = await fetch(`${APIURL}/subscribers`, {
method: "POST",
mode: "cors",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
return response.json();
};
window.onload = () => {
nameForm.method = "post";
nameForm.target = "_blank";
nameForm.action = "";
nameForm.addEventListener("submit", async e => {
e.preventDefault();
const firstName = document.getElementById("firstName").value;
const lastName = document.getElementById("lastName").value;
const email = document.getElementById("email").value;
let errors = [];
if (!firstName) {
errors.push("First name is required.");
}
if (!lastName) {
errors.push("Last name is required.");
}
if (!email) {
errors.push("Email is required.");
}
if (!/[^@]+@[^\.]+\..+/.test(email)) {
errors.push("Email is invalid.");
}
if (errors.length > 0) {
alert(errors.join(" "));
return;
}
try {
const response = await subscribe({
firstName,
lastName,
email
});
alert(`${response.firstName} ${response.lastName} has subscribed`);
} catch (error) {
alert(error.toString());
}
});
};

We replaced the then and callbacks with await . Then we can assign the resolved values of each promise as variables. Note that if we use await for our promise code then we have to put async in the function signature like we did in the above example. To catch errors, instead of chaining the catch function at the end, we use the catch clause to do it instead. Also, instead of chaining the finally function at the bottom to run code when a promise ends, we use the finally clause after the catch clause to do that instead.

async functions always return promises, and cannot return anything else like any other function that uses promises.

With the Fetch API and async and await syntax, we can make HTTP requests to servers much more easily than using the old XMLHttpRequest object. This is why now more and more web applications are using AJAX instead of refreshing the whole page on server side to get data.

The Startup

Medium's largest active publication, followed by +733K people. Follow to join our community.

John Au-Yeung

Written by

Web developer. Subscribe to my email list now at http://jauyeung.net/subscribe/. Email me at hohanga@gmail.com

The Startup

Medium's largest active publication, followed by +733K people. Follow to join our community.

John Au-Yeung

Written by

Web developer. Subscribe to my email list now at http://jauyeung.net/subscribe/. Email me at hohanga@gmail.com

The Startup

Medium's largest active publication, followed by +733K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store