Fetching in JavaScript: The Definitive Guide
Let’s imagine that you wake up and decide to make the next-generation decision-making app. Your idea is simple: you ask the site a question and every time you reload a page, you should get a “Yes” or a “No” randomly in response. Finally, something to help you solve tough decisions!
Luckily, there is an API that can do exactly this. The website yesno.wtf will randomly tell you “Yes” or “No” (and rarely “Maybe” according to their API description). In addition to that, it also gives you a GIF image URL related to the answer provided.
But wait, Helder, can’t we just use randomize “Yes” and “No” ourselves?
True, and that’s why this API is awesome. Being an extremely simple API is its best perk — perfect for learning the basics of fetching.
Building the required HTML elements
Let’s visit yesno.wtf and check out what their API responds with when you do a GET request:
{
"answer": "yes",
"forced": false,
"image": "https://yesno.wtf/assets/yes/2.gif"
}
This is an example of what you would get once you make a request in JSON format, so let’s just focus on this response. Looking at it, we have two elements that we want to use: “ answer” and “image”.
Let’s build some HTML:
<strong>Should I order a pizza today?</strong>
<p id="answer"></p>
<img id="gif" src="" />
While the first element isn’t necessary for this tutorial, it makes it more fun to learn 🙂 If you haven’t noticed already, there are blank places such as the answer element and gif img element. This is where the magic will happen.
So, let’s plug the response above directly into the elements, like so:
<strong>Should I order a pizza today?</strong>
<p id="answer">yes</p>
<img id="gif" src="https://yesno.wtf/assets/yes/2.gif">
Note: All I did was copy and paste, there was nothing else involved.
However, this will show the same answer and image every time (you shouldn’t be eating pizza every day). Enter fetching, your savior.
Understating Fetching
Fetching works a bit like a dialogue. When we’re fetching from the API yesno.wtf, the following conversation takes place:
– Hey yesno.wtf, my brother, work your magic and give me a randomly generated answer — Your website asks (through a GET request)
– Since you’ve asked nicely, I’ll return you this — yesno.wtf replies
{
"answer": "yes",
"forced": false,
"image": "https://yesno.wtf/assets/yes/2.gif"
}
Fetching answers
Fetching from an API in JS is extremely simple. This is all it takes:
fetch("https://yesno.wtf/api")
Surprised? fetch() makes by default a GET request to the URL of your choosing, so everything is good. However, doing just this is the same as going to Starbucks, ordering a Latte, and doing nothing with it afterward. What a waste of time right? You need to consider two things when fetching: you either get what you requested, or you get an error.
With this in mind, let’s add more code to the line above:
fetch("https://yesno.wtf/api")
.then(function (response) {
console.log(response); // Perfect, we got our response
})
.catch(function (error) {
console.error(error); // An error occurred while fetching
});
Can you guess the general idea behind this code? It’s about what we’ve talked about before. Go line by line and try to figure out what it means, as that’s how things get stuck in your head.
Note: fetch allows a variety of parameters to be passed. This is a basic guide on using fetch. For more information, check out the official documentation.
Handling the response from fetching
Let’s focus on the then part of the code above. What does “response” in …function (response)… contain? Well, if you execute the code above and check it out, it’s an object that looks like this:
{
"type": "cors",
"url": "https://yesno.wtf/api",
"redirected": false, "status": 200,
"ok": true,
"body": ReadableStream,
(...)
}
Hmm… this doesn’t look like what we were looking for. Where’s the object that we were promised from yesno.wtf!? Did they fool us? Turns out that the data we want is in there, we just need to choose in which way we want the response represented.
We can use the following properties from the response:
- response.text() — displays the data as text
- response.json() — displays the data as a JSON object (what we’re looking for in this case)
- response.formData() — displays the data as a FormData object
- response.blob() — displays the data as a Blob object
- response.arraybuffer() — displays the data as an ArrayBuffer object
Note: For more information on what each of these properties does, check out the official docs from MDN on the Response object.
So, which one should we choose? response.json() seems like the one we’re looking for, right? With this, let’s add a bit more code to what we had before:
fetch("https://yesno.wtf/api")
.then(function (response) {
return response.json(); // response.json() is asynchronous, so we need to chain another "then" to get what we want
})
.then(function (data) {
console.log(data); // { "answer": "yes", "forced": false, (...) }
})
.catch(function (error) {
console.error(error); // An error occurred while fetching
});
Note: If you’re wondering why we need to chain another .then to the code above, check out how works. It returns a Promise, so it needs to be handled asynchronously, just like above. If this is all too hard to understand, don’t worry, you don’t need to for now.
Awesome! We have all the elements we need. What’s missing? Outputting the data to the elements we created in the HTML. But first, let’s do a little exercise to see how you’re doing so far.
Exercise 1:
What should go on A, B, and C?
Try to describe succinctly what should go in each of these sections
fetch(A).then(B)
.then(function (data) { console.log(data); })
.catch(C);
Solution:
A: URL to fetch (+ optional parameters to pass as options to the fetching operation)
B: a function that receives the response (if fetching is successful) and returns the response in the way we want to read it.
C: a function that catches the error (if fetching is unsuccessful)
Outputting data to HTML
This part focuses on DOM manipulation. Since this guide is about fetching in JS, I won’t be talking about how to manipulate the DOM.
Let’s look at what we’re trying to accomplish once again (copied from “Building the required HTML elements)”:
<strong>Should I order a pizza today?</strong>
<p id="answer"></p>
<img id="gif" src="">
Hmm, so we need to make fetch() add text to the #answer element and at the same time add an image URL to the src of the #gif element.
Let’s take a look at the data that we receive from the API once again:
{
"answer": "yes",
"forced": false,
"image": "https://yesno.wtf/assets/yes/2.gif"
}
With this, we need to somehow copy the “answer” and “image “ into each HTML element, just like we did before manually. Great! *DOM manipulation enters the chat*
Exercise 2:
Where should we manipulate the DOM?
Try to infer where we should place the “answer” and “image” from the API data to the HTML element
fetch("https://yesno.wtf/api")
.then(function (response) {
A
})
.then(function (data) {
B
})
.catch(function (error) {
C
});
Solution:
B. A is where we turn the response into the format that we want while C is where you manage the error.
Bringing everything together
With everything I’ve said so far, let’s write the final code:
fetch("https://yesno.wtf/api")
.then(function (response) {
return response.json();
})
.then(function (data) {
document.getElementById("answer").textContent = "Answer: " + data.answer;
// TODO: Complete the code by replacing this with the image manipulation
})
.catch(function (error) {
console.error(error);
});
“Wait, what about the image part!?” — you ask, perplexed
As you can see in the comment above, isn’t this the perfect time for an exercise?
Exercise 3:
Complete the code by replacing the comment above
Take a look at the line above the comment and do something similar to the image element.
Solution:
fetch("https://yesno.wtf/api")
.then(function (response) {
return response.json();
})
.then(function (data) {
document.getElementById("answer").textContent = "Answer: " + data.answer;
document.getElementById("gif").src = data.image;
})
.catch(function (error) {
console.error(error);
});
Awesome, you’ve reached the end. Great job. Time for pizza?
If you have any questions or comments, please post them below, I’ll be replying as much as I can.