Noisy Neighbor Perfect is a verb, not a noun.

Tmtowtgi

Intro

Perl popularized the concept There’s More Than One Way To Do It (which, depending on who you ask, is either awesome or just confusing). JavaScript is similarly good at giving budding programmers 2^32 ways of doing most anything. In a prior post we briefly evaluated how to do simple HTTP GETs for querying an API… as an homage to Perl monks everywhere, let’s explore how There’s More Than One Way To GET It (or POST, PUT…whatever).

NOTE: I tend not to use semi-colons in JavaScript…this is not a desire to offend or participate in any holy wars. Feel free to imagine semi-colons anywhere you see fit, or better yet watch this monolog that is both amusing and enlightening.

NOTE’: Please read this, or anything I ever create, with a sense of humor. :-)

Context

As a convenient use case, we’ll build a minimalist Bitcoin price checker because, well, everyone’s doing Bitcoin stuff and peer pressure is real. We’ll use the Coindesk API.

For the sake of brevity, I won’t repeat this again in all the examples, but we declare some important constants in the top of our JavaScript which point to the API endpoint and element we’ll be updating with the current Bitcoin price:

const API = 'https://api.coindesk.com/v1/bpi/currentprice.json'
const PRICE = document.querySelector('#price')

For the examples below, common HTML boilerplate is also used… here’s what that looks like so the JavaScript makes more sense:

<html>
    <head>
        <link rel="stylesheet" href="style.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    </head>
    <body>
        <h1>Bitcoin Price Checker</h1>
        <ul>
            <li id="btnXHR">XHR</li>
            <li id="btnFetch">Fetch</li>
            <li id="btnJquery">jQuery</li>
            <li id="btnAxios">Axios</li>
        </ul>
        <p id="price">Push a button to get started...</p>
        <script src="bitcoinGetter.js"></script>
    </body>
</html>

Yep, that’s it… Quite hideous, but the UI is not the point and we don’t want it to be a distraction. In fact, this should be simpler – I started getting sucked into the black hole that is endless tweaking of HTML and CSS. :-) All you need to note is that we setup some unique element ids to make our selector queries easier and import both jQuery and Axios which we’ll use later on.

or just use the source, Luke (or Lukette, or whatever your name, hair color, country of origin, personal pronoun, etc. happens to be – source is equally good for us all).

XHR

First, let’s travel back in time… a time when AJAX (Asynchronous JavaScript And XML) was new. Obviously, it was still new, since today it would be called AJAJ (what doesn’t spew JSON these days?). This was a time when Single Page Apps and other now-commonly-accepted hotness did not exist, so the ability to make asynchronous HTTP requests obviously got people very excited.

Strictly speaking, the X doesn’t just stand for XML, but more specifically XMLHttpRequest. This built-in object is still used to make HTTP requests in JavaScript today. Thankfully, modern implementations speak JSON since it makes more sense in the Javascript ecosystem. As I’m sure you noticed, XMLHttpRequest is much nicer to bandy about if we abbreviate it XHR, so that’s what is commonly done (and who doesn’t love acronyms).

That’s great trivia fodder you say, but how does it work? Here you go:

// XHR

const btnXHR = document.querySelector('#btnXHR')

btnXHR.addEventListener('click', function() {
    let XHR = new XMLHttpRequest()
    XHR.onreadystatechange = function() {
        if (XHR.readyState == 4 && XHR.status == 200) {
            PRICE.textContent = JSON.parse(XHR.responseText).bpi.USD.rate + ' USD'
        }
    }
    XHR.open('GET', API)
    XHR.send()
})

Nothing surprising here, assuming you understand at least a few things:

  • We need to instantiate a new XHR object before we can do anything useful (hence the use of new).
  • onreadystatechange (love that name) is an event handler called any time our new XHR’s readyState attribute changes.
  • readyState has five possible states_ (0-4), with 4 signifying the request is complete.

If you find the open and send confusing, the docs help…but just think of open as setting up the request, and send, well, sending it. Once sent, the state changes will propagate, and assuming it completes (and we get a 200 OK) PRICE.textContent is updated.

Why start with XHRs? They are the foundational element upon which everything below is built!

Fetch

Another native way (aside from https.get which we discussed in the past) is fetch. This is a newer addition to the language, as evidenced by its use of promises. Oooo ahhh promises, you say! Let’s see it in action before we get to an unfortunate secret (if secret is another name for behavior described in the documentation):

// Fetch

const btnFetch = document.querySelector('#btnFetch')

btnFetch.addEventListener('click', function() {
    fetch(API)
        .then(function(res) {
            res.json()
                .then(function(data) {
                    PRICE.textContent = data.bpi.USD.rate + ' USD'
                })
        })
        .catch(function(err) {
            console.log(err)
        })
})

Pretty neat, huh? The main things to note here are the use of .then and .catch to handle promises, as well as the built-in .json() method which replaces our use of JSON.parse() above. Nice, clean, modern… but not well supported (yet). The Fetch API docs reveal IE is completely out in the cold at this point, which might be a show-stopper for you.

jQuery

Good old jQuery. If there was ever a more simultaneously revered and dissed workhorse among us, I haven’t seen it…at least not since the last watercooler conversation over vim vs emacs. Though, technically, I guess that is a conversation about two equally dissed workhorses (depending whom you talk to). I digress.

While not as popular as it used to be, jQuery is still full-featured, extremely useful in some circumstances, and given past popularity you might need to support it regardless of personal opinions. For the record, I don’t have anything against it – just be sure you need to do more than make an HTTP request before pulling in a large dependency!

Here goes:

// jQuery

$('#btnJquery').click(function() {
    $.getJSON(API)
        .done(function(data) {
            $('#price').text(data.bpi.USD.rate + ' USD')
        })
        .fail(function(err) {
            console.log(err)
        })
})

Gone is the querySelector, or more accurately…it’s been disguised as $. Different syntax, but we still bind an anonymous function to a click listener. Inside, we use jQuery’s getJSON method to handle turning the HTTP response into a useful object. That is two things jQuery has going for it – no shortage of documentation or utility methods!

Axios

Last, but certainly not least, Axios is a tremendously popular (i.e. almost 40k stars on GitHub at the time of this writing) HTTP client library. It is promise-based, lightweight, and well-supported.

// Axios

const btnAxios = document.querySelector('#btnAxios')

btnAxios.addEventListener('click', function() {
    axios.get(API)
        .then(function(res) {
            PRICE.textContent = res.data.bpi.USD.rate + ' USD'
        })
        .catch(function(err) {
            console.log(err)
        })
})

The promise handling looks similar to earlier examples but gone is any reference to JSON-related methods…because the library is doing the transformation automagically. Pretty sweet! Axios is also highly-configurable and supports concurrency that is actually easy to understand:

// Community example of multiple requests with Axios...

function A() {
  return axios.get(API + '/A');
}

function B() {
  return axios.get(API + '/B');
}

axios.all([A(), B()])
  .then(axios.spread(function (a, b) {
    // Safely use a and b!
  }));

Summary

So, there you have it… more ways than anyone ever needed to make HTTP requests in JavaScript. Needless to say, the examples above were all client-side, but could just as easily have been done in Node.js. For those requiring imports, just replace the <script></script> tags with npm install axios or similar.

Last but not least, I want to give a very loud shout out to Udemy’s Advanced Web Developer Bootcamp. The use case and examples here were an amalgamation of things picked up there. If you’re looking for a good overview of modern web development, it’s a great course – and I am not affiliated with Udemy or the course authors in any way…so hopefully that counts for something. :-)

Thanks for reading!

PS: My examples use USD simply because it is my local currency, and kept the code a bit cleaner… At the time of writing, the Coindesk API can return EUR, GBP and USD. As a fun exercise, clone the repo and refactor to support your favorite, or let the user select the desired currency!