If you're the type of person to read technical Javascript posts in your free time (you are), you don't need me to tell you that JQuery is dead. JQuery themselves have proclaimed JQuery to be dead. The only cool thing about JQuery is who can remove it from their legacy stack the fastest, which begs the question: why is the third most popular page on this site an old post about JQuery?
Maintaining a blog of tutorials has taught me a lot about the gap between perception and reality. While we content publishers sling Medium posts from our ivory towers, we quickly create a perception of what "everybody" is doing, but it turns out "everybody" only includes individuals who are exceptionally visible. That demographic makes up significantly less than 10-20% of the active workforce. I would have assumed any post with the word "React" would immediately explode, when in reality people are more interested in using Handlebars with ExpressJS (I'm not proud of that post by the way, please don't read it).
I want to provide an alternative to using AJAX calls when interacting with REST APIs to clear my conscious of ever enabling bad behavior in the first place. Hopefully, those who have lost their way might find something to take from it. Considering how deep I've gone down the GraphQL rabbit hole myself, this may be the last chance to bother writing about REST at all.
Library of Choice: node-fetch
Like everything in Javascript, there are way too many packages doing the same thing and solving the same problem. Making API requests is no exception. http is a bit primitive, request breaks when building with Webpack, r2 seems like a pointless clone, and so on. Don't get me started with async libraries with 40 different methods for chaining requests. Who is gunslinging API requests to the point where we need this many options to pipe or parallel API requests anyway?
After using all of these libraries, node-fetch is the weapon of choice for today. To put it simply: it's straightforward, and the only one that actually works out of the box with Webpack without absurd configuration nonsense.
The other request library worth mentioning is isomorphic-fetch, which is intended to be a drop-in replacement for node-fetch. isometric-fetch mimics the syntax of node-fetch, but impressively works on both the client and server-side. When used on the client side, isomorphicfetch works by first importing the es6-promise
polyfill.
Getting Set Up
Start a Node project and install node-fetch:
In the JS file we'd like to make a request, we can reference node-fetch using require():
Creating a node-fetch Request
We'll start with the most basic GET request possible:
Indeed, that's all it takes a base level. Without specifying a method, node-fetch assumes we're making a GET request. From we generate JSON from the request body and print the result to the console.
Chances are you're not going to get much value out of any request without passing headers, parameters, or a body to the target endpoint. Here's how we'd make a more complicated (and realistic) POST call:
That's more like it: now we're passing headers and a JSON body. If needed, the fetch() method also accepts a credentials
parameter for authentication.
Note that we are avoiding callback hell by keeping logic that utilizes the response JSON in our then() arrow functions. We can chain together as many of these statements as we want.
Properties of a Response
The response object contains much more than just the response body JSON:
res.status
is particularly handy when building functionality around catching errors:
Making Asynchronous Requests
Chances are that when we make an API request, we're planning to do something with the resulting data. Once we start building logic which depends on the outcome of a request, this is when we start running into Callback Hell: perhaps the worst part of JavaScript. In a nutshell, JavaScript will not wait for a request to execute the next line of code, therefore making a request and referencing it immediately will result in no data returned. We can get around this by using a combination of async and await.
async
is a keyword which denotes that a function is to be executed asynchronously (as in async function my_func(){...}
). await
can be used when calling async
functions to wait on the result of an async function to be returned (ie: const response = await my_func()
).
Here's an example of async/await in action: