Ajax Requests

Have you ever wondered what happens after you click a “Submit” button on a web page? For instance, if you are submitting information, where does the information go? How is the information processed? The answer to the previous questions revolves around HTTP requests.

There are many types of HTTP requests. The four most commonly used types of HTTP requests are GET, POST, PUT, and DELETE. In this lesson, we’ll cover GET and POST requests. 

With a GET request, we’re retrieving, or getting information from some source (usually a website). For a POST request, we’re posting information to a source that will process the information and send it back.

In this lesson, we will explain how to make GET and POST requests by using JavaScript’s XHR object. We’ll also incorporate query strings into our requests.

HTTP Requests

One of JavaScript’s greatest assets is its non-blocking properties, or that it is an asynchronous language.

Websites, like newspaper websites, take advantage of these non-blocking properties to provide a better user experience. Generally, a site’s code is written so that users don’t have to wait for a giant image to load before being allowed to read the actual article—rather, that text is rendered first and then the image can load in the background.

JavaScript uses an event loop to handle asynchronous function calls. When a program is run, function calls are made and added to a stack. The functions that make requests that need to wait for servers to respond then get sent to a separate queue. Once the stack has cleared, then the functions in the queue are executed.

Web developers use the event loop to create a smoother browsing experience by deciding when to call functions and how to handle asynchronous events. We’ll be exploring one system of technologies called Asynchronous JavaScript and XML, or AJAX.

XHR GET Requests

Asynchronous JavaScript and XML (AJAX), enables requests to be made after the initial page load. Initially, AJAX was used only for XML formatted data, now it can be used to make requests that have many different formats. Similarly, the XMLHttpRequest (XHR) API, named for XML, can be used to make many kinds of requests and supports other forms of data.

We are going to reconstruct XHR GET request boilerplate code step-by-step until we have written a complete GET request.

const xhr = new XMLHttpRequest();
const url = ‘https://api-to-call.com/endpoint’;
xhr.responseType = ‘json’;
xhr.onreadystatechange = () => {
  if (xhr.readyState === XMLHttpRequest.DONE){
    return xhr.response;
  }
}

xhr.open(‘GET’, url);
xhr.send();

 

A query string contains additional information to be sent with a request. The Datamuse API allows us to retrieve more specific data with query strings attached to the request URL.

A query string is separated from the URL using a ? character. After ?, you can then create a parameter which is a key value pair joined by a =. Examine the example below:

‘https://jsonplaceholder.typicode.com/posts?id=1’

 

If you want to add an additional parameter you will have to use the & character to separate your parameters. Like so:

‘https://jsonplaceholder.typicode.com/posts?id=1&userid=1’

 

XHR POST Requests

The major difference between a GET request and POST request is that a POST request requires additional information to be sent through the request. This additional information is sent in the body of the post request.

This is a sample code to make POST request:

const xhr = new XMLHttpRequest();
const url = ‘https://api-to-call.com/endpoint’;
const data = JSON.stringify({id: ‘200’});

xhr.responseType = ‘json’;

xhr.onreadystatechange = () => {
  if(xhr.readyState === XMLHttpRequest.DONE){
    return xhr.response;
  }
}

xhr.open(‘POST’, url);
xhr.send(data);

 

AJAX in ES6

To make asynchronous event handling easier, promises were introduced in JavaScript in ES6. A promise is an object that handles asynchronous data. A promise has three states:

  • pending : when a promise is created or waiting for data.
  • fulfilled : the asynchronous operation was handled successfully.
  • rejected : the asynchronous operation was unsuccessful.

The great thing about promises is that once a promise is fulfilled or rejected, you can chain an additional method to the original promise.

We will explain how to use fetch(), which uses promises to handle requests. Then, we will simplify requests using async and await.

fetch() GET Requests

The first type of requests we’re going to tackle are GET requests using fetch(). The fetch() function:

  • Creates a request object that contains relevant information that an API needs.
  • Sends that request object to the API endpoint provided.
  • Returns a promise that ultimately resolves to a response object, which contains the status of the promise with information the API sent back.

We are going to reconstruct the boilerplate code necessary to create a GET request using the fetch() function step-by-step.

fetch(‘https://api-to-call.com/endpoint’).then(response => {
  if (response.ok) {
    return response.json();
  }
  throw new Error(‘Request failed!’);
}, networkError => {
  console.log(networkError.message);
}).then(jsonResponse => {
  return jsonResponse;
});

 

fetch() POST Requests

Now, Let’s see how to use fetch() to construct POST requests.This codei is a complete POST request using fetch() and .then().

fetch(‘https://api-to-call.com/endpoint’, {
  method: ‘POST’,
  body: JSON.stringify({id: “200”})
}).then(response => {
  if(response.ok){
  return response.json(); 
  }
throw new Error(‘Request failed!’);
}, networkError => {
  console.log(networkError.message);
}).then(jsonResponse => {
  console.log(jsonResponse);
})

 

The request returns a Promise which will either be resolved or rejected. If the promise resolves, you can use that information and the ok status.

async GET Requests

Let’s take a minute to appreciate what you’ve accomplished so far:

  • used fetch() to make GET and POST requests.
  • check the status of the responses coming back
  • catch errors that might possibly arise
  • taking successful responses and rendering it on the webpage

That is fantastic! It’s the basis of how the internet works!

Now we’re going to take what you’ve learned about chaining Promises and make it simpler using functionality introduced in ES8: async and await. You read that right, you did the hard part already, now it’s time to make it easier.

The structure for this request will also be slightly different. Notice the new keywords async and await, as well as the try and catch statements.

We are going to walk through and recreate the boilerplate code necessary to create a GET request using the async and await.

const getData = async () => {
  try {
    const response = await fetch(‘https://api-to-call.com/endpoint’);
    if (response.ok) {
      const jsonResponse = await response.json();
      return jsonResponse;
    }
    throw new Error(‘Request failed!’);
  } catch (error) {
    console.log(error);
  }
}

 

Here are some key points to keep in mind as we walk through the code:

  • Using an async function that will return a promise.
  • await can only be used in an asyncfunction. await allows a program to run while waiting for a promise to resolve.
  • In a try…catch statement, code in the try block will be run and in the event of an exception/error, the code in the catch statement will run.

async POST Requests

An async POST request requires more information to work. Now we’re going to piece together a POST request using async and await.

const getData = async () => {
  try {
    const response = await fetch(‘https://api-to-call.com/endpoint’, {
      method: ‘POST’,
      body: JSON.stringify({id: 200})
    })
    if(response.ok){
      const jsonResponse = await response.json();
      return jsonResponse;
    }
    throw new Error(‘Request failed!’);
  } catch(error) {
    console.log(error);
  }
}

 

Review

You’ve done an amazing job navigating through making XHR GET and POST requests! Take some time to review the core concepts before moving on to the next lesson.

  1. JavaScript is the language of the web because of its asynchronous capabilities. AJAX, which stands for Asynchronous JavaScript and XML, is a set of tools that are used together to take advantage of JavaScript’s asynchronous capabilities.
  2. There are many HTTP request methods, two of which are GET and POST.
  3. GET requests only request information from other sources.
  4. POST methods can introduce new information to other sources in addition to requesting it.
  5. GET requests can be written using an XMLHttpRequest object and vanilla JavaScript.
  6. POST requests can also be written using an XMLHttpRequest object and vanilla JavaScript.
  7. Writing GET and POST requests with XHR objects and vanilla JavaScript requires constructing the XHR object using new, setting the responseType, creating a function that will handle the response object, and opening and sending the request.
  8. To add a query string to a URL endpoint you can use ? and include a parameter.
  9. To provide additional parameters, use &and then include a key-value pair, joined by =.
  10. Determining how to correctly write the requests and how to properly implement them requires carefully reading the documentation of the API with which you’re working.

Let’s recap on the concepts covered in the fetch() request:

  1. GET and POST requests can be created a variety of ways.
  2. Use AJAX to asynchronously request data from APIs. fetch() and async/await are new functionalities developed in ES6 (promises) and ES8 respectively.
  3. Promises are a new type of JavaScript object that represent data that will eventually be returned from a request.
  4. fetch() is a web API that can be used to create requests. fetch() will return promises.
  5. We can chain .then() methods to handle promises returned by fetch().
  6. The .json() method converts a returned promise to a JSON object.
  7. async is a keyword that is used to create functions that will return promises.
  8. await is a keyword that is used to tell a program to continue moving through the message queue while a promise resolves.

await can only be used within functions declared with async.