Mikke.Learns

Connecting to a server with XMLHttpRequest, part 1

February 16th, 2019

The way I understand it, the XMLHttpRequest() is a JavaScript object often used in AJAX programming to interact with a server. It lets us retrieve data and update the web page without needing to reload.

The XMLHttpRequest() object is a so-called constructor and needs to be initialized with a “new” keyword.

const request = new XMLHttpRequest();

It must also be called before any other of the XMLHttpRequest objects method calls. And even though the object starts with “XML”, it can be used to retrieve any kind of data. It can also work with other protocols like FTP and files, and not just HTTP.

Connecting to pokeapi

In this project, we are going to connect to the pokeapi.co and fetch a random Pokémon with name, image and some other information.

Step one is to create some simple HTML and CSS and then add an event listener to a button. Every time we click it, we send a new request to pokeapi.co and get a Pokémon in return.

First, we create a new XMLHttp object. As mentioned above, this has to come before any of the other methods, like open and send. We must also call open() before we can use send() to send the request.

// Select the button (DOM element) const button = document.querySelector('#loadChar'); // A function that sends a request to the server let requestCharacter = function () { const url = 'https://pokeapi.co/api/v2/pokemon/1/'; const request = new XMLHttpRequest(); request.open("GET", url); request.send(); } // The event listener (what happens when we click the button on the webpage) button.addEventListener('click', requestCharacter);

The open() method

The open() method initializes a newly created request. It can be called with five parameters; method, url, async, user and password. Method and url are a minimum.

  • Method: The HTTP request to use, like “GET”, “PUT”, “POST” and “DELETE”.

  • Url: A string with the url to send the request to.

  • Async: A boolean parameter, defaulting to true. It’s an indication of whether or not to perform the operation asynchronously.

  • User and password: Optional user and password if authentication is needed.

The send() method

This method is what actually sends the request to the server. If it’s asynchronous (standard) the method returns as soon as the request is sent, and the results are returned using events.

If the request is synchronous, the method won’t return until the response from the server has arrived. This can afflict the user experience of our site. We may end up waiting for the response from the server before the rest of the page loads.

The return data

xmlhttp1

When we now click the button, we send a new request to the server. Nothing happens on the webpage yet, but if we take a look at the network tab in the developer tools, we can see that we successfully made a connection. Data is coming through to us:

xmlhttp2

But how do we control the process of connecting to the server? How do we use the data? And what if there is an error? The XMLHttpRequest-object has a lot of useful properties and events that can help us out.

First, let’s see what the object can tell us about the server connection.

readyState

There are five different states that the XMLHttpRequest client goes through when connecting to a server:

  • 0: Unsent - The client has been created. open() is not yet called.

  • 1: Opened - open() has been called.

  • 2: Headers_received - send() has been called, and headers and status are available.

  • 3: Loading - Downloading. responseText has partial data.

  • 4: Done - The operation is complete.

If we console.log the XMLHttpRequest object…

// Select the button (DOM element) const button = document.querySelector('#loadChar'); // A function that sends a request to the server let requestCharacter = function () { const url = 'https://pokeapi.co/api/v2/pokemon/1/'; const request = new XMLHttpRequest(); console.log(request); request.open("GET", url); request.send(); } // The event listener (what happens when we click the button on the webpage) button.addEventListener('click', requestCharacter);

…we can see that the readyState is 4:

xmlhttp4

That’s because by the time we receive the data, the operation is of course done. But we can also reach state 4 by failing to connect. It simply indicates whether or not the operation itself is done.

So, is there a way to check the ready state before it reaches 4? And maybe do something at certain states? Absolutely. That’s where onreadystatechange comes in.

onreadystatechange

onreadystatechange is an eventHandler that gets called every time the ready state (as described above) changes. It contains a callback function. If we console.log readyState inside this function, we can see the process going from 1 to 4 (preferably).

Notice that one console.log is also outside the eventHandler. That’s to be able to get the 0 state. The reason is that the callback function only fires when there is a change in the ready state. If so, the number goes up to 1.

let requestCharacter = function () { const url = 'https://pokeapi.co/api/v2/pokemon/1/'; const request = new XMLHttpRequest(); console.log(request.readyState); // When the ready state changes we use a function. request.onreadystatechange = function () { console.log(request.readyState); } request.open("GET", url, true); request.send(); }

xmlhttp5

More info with status

The status property returns a number. This number is actually the HTTP status code of the XMLHttpRequest.

There are a lot of HTTP status codes. The most common is probably 404 “page not found”, 403 “forbidden” and 503 “service unavailable”.

What we want in this case, is status 200 “OK”, the standard response for successful HTTP requests.

Lets console log it and see what we get:

let requestCharacter = function () { const url = 'https://pokeapi.co/api/v2/pokemon/1/'; const request = new XMLHttpRequest(); console.log(request.readyState); console.log(request.status) // When the ready state changes we use a function. request.onreadystatechange = function () { console.log(request.readyState); console.log(request.status) } request.open("GET", url, true); request.send(); }

Again, we console log it before the onreadystatechange as well as inside the callback function. This is what we get:

xmlhttp6

At readyState 0 there is no status. At readyState 1, the status is 0. When we get to readState 2,3 and 4 in this case, the readyState changes to 200, meaning we got a successful HTTP request.

This means that we should check for status 200 and readyState 4 before writing any additional code to work with the response from the server.

Ready state 4 and status 200

Since we now know what to look for to be sure that we have made a connection to the server, we can use that in onreadystatechange mentioned above.

When the status is 200 and the readyState is 4, we want to perform an operation:

let requestCharacter = function () { const url = 'https://pokeapi.co/api/v2/pokemon/1/'; const request = new XMLHttpRequest(); // When the ready state changes we use a function. request.onreadystatechange = function () { if(request.readyState == 4 && request.status == 200 ) { console.log('Success: ' + request.readyState +', ' + request.status); console.log(request.responseText); } } request.open("GET", url, true); request.send(); }

As we can see, we are now connected and ready to go. We have got a status 200 and ready state 4, as well as the response text:

xmlhttp7

Summary

XMLHttpRequest() is a constructor object used to connect to a server or other protocols and retrieve data asynchronously. It has a lot of methods, properties, and events to help us control the connection process as well as the data that is returned to us.

  • new XMLHttpReques() has to be called before the other methods.

  • open() must be called before send()

  • open() can be called with five parameters; method, url, async, user and password. Method and url are a minimum.

  • The send() method sends the request to the server. It can be called asynchronously or synchronolously.

  • readyState tells us what state the connection process is in. It ranges from 0 to 4, where 4 is “done”.

  • onreadystatechange is an event handler with a callback function that fires every time the ready state changes.

  • status return the HTTP status code of the XMLHttpRequest, like 404, 506 and 200 which is what we want. That means “OK”.

  • We can write an if statement inside our callback function in onreadystatechange to check for status 200 and readystate 4: if(request.readyState == 4 && request.status == 200)