Ajax Calls Using Fetch

I've got to level with you, when I made this post about AJAX almost all of my experience with AJAX was with jQuery.

When I was writing that post, I figured I'd do with AJAX what I had been doing with other topics, namley try to do the thing without any of the libraries I usually use and see how far I got.

Problem is, you have to write all this boilerplate code I didn't get into just to make sure your AJAX calls are compatible across browsers. It's way too complicated for what it is. There's a reason people usually use libraries for this kind of thing.

Thankfully, there's an effort to make this whole AJAX thing easier, the fetch api. It's a proposed new standard for handling AJAX calls in the browser.

To demonstrate, I'll create a small project like I always do:

https://github.com/NerdcoreSteve/fetch

Here's the code for the backend:

const  
    express = require('express'),
    body_parser = require('body-parser'),
    app = express()

app.use(express.static('public'))  
app.set('view engine', 'pug')  
app.use(body_parser.urlencoded({extended: false}))  
app.use(body_parser.json())

app.get('/', function (req, res) {  
    res.render('index')
})

app.post('/ajax', function (req, res) {  
    res.json({
        message:
            `This comes from an AJAX POST call!`
            + `The message sent to the server was `
            + `"${req.body.data.message}"`
    })
})

app.listen(3000, function () {  
    console.log('Example app listening on port 3000!')
})

From the top: we've got your basic setup code for express. Then we've got our routes, the first one being the index page to our little app, the next one being a response to a POST request.

The markup isn't anything special, just a header and a button:

html  
    head
        title AJAX
    body
        h1(id='message') You haven't clicked it yet
        button(id='clickit') click it
    script(src='js/main.js')

Here's the code for the front-end:

require('whatwg-fetch')

document.querySelector('#clickit').onclick = () =>  
    fetch('/ajax', {
        method: 'post',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            data: {
                message: 'You are a penguin'
            }
        })
    })
    .then(function(response) {
        return response.json()
    }).then(function(json) {
        console.log('parsed json', json)
    }).catch(function(ex) {
        console.log('parsing failed', ex)
    })

In order to get this to work, the front-end is going to need to have the whatwg-fetch npm module. whatwg-fetch is github's implementation of the fetch api, which is not yet implemented in all browsers.

Also, depending on your browser version, you might need the babel promise polyfill. I didn't need it in the versions of Chrome, Firefox, and Safari that I've got, so you probably don't need it either, but I thought I'd mention it just in case.

With all that out of the way, what's going on with the front-end code?

From the top: we include whatwg-fetch. No need to assign it to a variable, it'll just float around globally for us to use.

Next, we've got an on-click on our button. The callback we give it is what does the ajax call.

First we call the fetch function. We tell it we're going to make a POST request (just replace this bit with get, put, delete or whatever you need when you use fetch), set the header for JSON data, and give it a payload in the form of a string-ifed JSON object.

Next, our server responds. How fetch handles this response may look a little weird to you if you've never encountered promises before.

I'll blog about them in more detail in a later post, but for now I'll tell you that promises are a new way of handling asynchronous code in JavaScript. Instead of using simple callbacks, we create an object called a promise. A promise is an object that represents a value you'll get in the future. It has a number of methods, but for now we'll focus on then and catch.

A promise's then method takes a callback that will execute when the asynchronous event the promise represents happens. What's cool about then, is that you can return another promise in your then callback to create a chain of asynchronous events.

To handle this new promise, just call .then on your .then and you can handle this new asynchronous event without creating a pyramid of callbacks. You can chain .thens as long as you want: .then(f1).then(f2).then(f3)...

In this example, fetch returns a promise that resolves when we get the response back from our server. The response is an object with a method called json, which returns another promise. We handle this promise by calling .then on our .then.

Finally, we put a .catch at the end of this chain just in case something goes wrong. One of cool things about a promise chain is that you can make it as long as you like and put a catch at the end to handle any errors that might occur along your promise chain.

I think this is a nicer way to handle AJAX, but it's not the coolest part. Wait until I get to blog at you about generators... :)

Looking for a software developer?