Code-Along: Dog Fetcher
Follow these instructions to build a website that will provide the user with some pictures of dogs.
Click here to view the Dog Fetcher Starter project. Remix the project to begin the activity.
Part One: Background
Typically, dogs play fetch. In this activity, your code is going to be playing fetch, and the things that your code will be fetching will be dogs!
The Starter Code
The starter project has quite a bit of code, but it's all HTML and CSS! In the index.html file, there are a few elements of note:
- An
<input>
with anid
of"num-dogs"
- A
<button>
with anonclick
of"getDogs()"
- An
<img>
with anid
of"loading"
- This is currently hidden using CSS
- A
<div>
with anid
of"dog-imgs"
All of these elements will be necessary to make the website functional.
NOT WORKING: The shibe.online API
Note: the shibe.online API appears to be down. Use give-me-dogs.glitch.me/dogs instead. You can check out the source code too.
The code needs something to fetch, and luckily, there is an API that provides random pictures of shiba inu dogs! These adorable pups are also known as "shibes" in internet parlance - hence the name, shibe.online. Take a look at the homepage to learn more about how the API works.
The base url is https://shibe.online/api/shibes
. For the purposes of this activity, the only relevant query parameter will be count
. The response will be a JSON array of strings; each one a URL pointing to a picture of a shibe.
Putting it all together, here's an example URL: https://shibe.online/api/shibes?count=3
The response should look something like this:
[
"https://cdn.shibe.online/shibes/039e86853cb65ed16cb3823a4fd9528ae374cfec.jpg",
"https://cdn.shibe.online/shibes/6179b94f4e16762f29e69b48a45f16372b11ed72.jpg",
"https://cdn.shibe.online/shibes/e0419f6e1f00e800bada84233b0bad86723077ed.jpg"
]
Try opening one of the URLs to see the picture! Here is one of them:
The Plan
To utilize this API, the code should:
- Make a request to the base URL using
fetch
- Use the
<input>
to determine thecount
to pass in as a query parameter
- Use the
- Extract the image URLs from the response
- Create new
<img>
elements, one for each URL returned
Part Two: Button Begins 🦇
Currently, there is no JavaScript code in the project. That's bad! Start things off by hooking up the <button onclick="getDogs()">
with a new function definition.
- Open the script.js file for editing
- Define a new function named
getDogs
- In the body of the function, create a new variable named
loadingImg
- Set
loadingImg
to grab the<img id="loading">
picture- Use
document.querySelector
for this
- Use
- On the next line, set the
style.display
of the image to"inline-flex"
- This will make the loading indicator appear
At this point, run the project, click the "Get Dogs" button, and verify that the loading indicator image appears! The code should look something like this:
function getDogs() {
let loadingImg = document.querySelector("#loading");
loadingImg.style.display = "inline-flex";
}
Part Three: Fetching Two Dogs 🐕🐕
Now the button is ready, so it's time to try to get some dogs! To start, the code can ignore the <input>
and just try to get two dogs.
Trying to Fetch with fetch
Use the fetch
function to send a request out to the API to try to get some shibe pics.
- Make a new line in the body of the
getDogs
function - Create a new variable named
response
- Set
response
to equal a call tofetch
- Pass in `
https://give-me-dogs.glitch.me/dogs?count=2
` as the URL
- Pass in `
- Under that, create a variable named
responseJson
- Set
responseJson
to a call to thejson()
function on theresponse
variable - Finally, call
alert
onresponseJson
to display the result
With that, run the code, click the "Get Dogs" button again, and see what happens. It might not quite work... it should display a pop-up, but there is an issue with this code:
let response = fetch(`https://give-me-dogs.glitch.me/dogs?count=2`);
let responseJson = response.json();
alert(responseJson);
Catching an Error with try
/catch
So something is wrong, and it may be possible to debug it, but it is also possible for the code itself to catch the error! Use the try
/catch
structure to try to figure out what is happening.
- Above the current variables, declare
response
andresponseJson
without giving them a value- This will allow the code to use them in and out of the
try
block
- This will allow the code to use them in and out of the
- Under that, create a
try
/catch
structure- Start with the
try
keyword - Then, add curly brackets
{
and}
- After that, add the
catch
- For the
catch
, add parentheses(
and)
- Put
e
within the parentheses to represent the error - Finally, add another set of curly brackets
{
and}
- Start with the
- Move the original variable sets into the
try
block- Make sure to get rid of the
let
because these already exist
- Make sure to get rid of the
- In the
catch
block, callalert
on the error - Also in the
catch
block,return
from the function
The modified code should look something like this:
let response, responseJson;
try {
response = fetch(`https://give-me-dogs.glitch.me/dogs?count=2`);
responseJson = response.json();
} catch (e) {
alert(e);
return;
}
Now, try running the project and clicking the button. It still will not work, but at least the error should appear in a pop-up! It should say the following:
TypeError: response.json is not a function
Fixing the Error with Asynchronicity
Hmm... why would response.json
not be a function? The fetch
call should return a Response
object... or should it? What does the fetch
function return again?
The fetch
function returns a Promise object - so it must be await
ed to yield the actual result!
- Start by adding the
async
keyword to thegetDogs
function definition - Next, add the
await
keyword in front of thefetch
call - Also, add the
await
keyword in front of thejson()
call - Additionally, add a
finally
block after thecatch
block - There, make the loading indicator disappear
- Use
.style.display = "none"
to accomplish this
- Use
- Additionally, for testing, purposes, call
alert
onresponseJson
Run the program, click the "Get Dogs" button again, and verify that some dog image URLs appear! Copy and paste one into a new tab to see a shibe like this.
At this point, the entire code in the script.js file should look something like this:
async function getDogs() {
let loadingImg = document.querySelector("#loading");
loadingImg.style.display = "inline-flex";
let response, responseJson;
try {
response = await fetch(`https://give-me-dogs.glitch.me/dogs?count=2`);
responseJson = await response.json();
} catch (e) {
alert(e);
return;
} finally {
loadingImg.style.display = "none";
}
alert(responseJson);
}
Part Four: Displaying the Images
The fetch
request is actually working! The JavaScript code is talking to an API and retrieving something from the internet. The next step is to display the results in a nicer way.
Prepping the Container
There is already a <div id="dog-imgs">
container in the index.html file - this will hold the new pictures of dogs. The first step will be to grab it, and clear out anything that's in it.
- Remove the
alert
from the body of thegetDogs
function - In its place, create a new variable named
dogImgsDiv
- Use
document.querySelector
to grab the<div id="dog-imgs">
and store it in the variable - Under that, set the
innerHTML
of thedogImgsDiv
to be""
The code for this part should look something like this:
let dogImgsDiv = document.querySelector("#dog-imgs");
dogImgsDiv.innerHTML = "";
Looping the Response
The goal is to create one picture element for each picture URL in the response. The responseJson
object should be an array that stores something like this:
[
"https://images.dog.ceo/breeds/shiba/shiba-9.jpg",
"https://images.dog.ceo/breeds/shiba/shiba-10.jpg"
]
The forEach
array function will be perfect for this! First, establish the loop.
- Make a new line at the bottom of the
getDogs
function - There, call the
forEach()
function onresponseJson
- Between the parentheses, create a new arrow function
- It should have one parameter:
dogUrl
- It should have an arrow:
=>
- It should have curly brackets:
{
and}
- It should have one parameter:
The loop code should look something like this:
responseJson.forEach(dogUrl => {});
Adding Each Image to the Container
Now the code is setup to run a block for every image URL retrieved from give-me-dogs.glitch.me. For each of them, a new <img>
element should be created and added to the dogImgsDiv
container!
- Within the
forEach
arrow function body, make a new line - There, create a new variable named
newDogImg
- Set
newDogImg
to be a new"img"
element usingdocument.createElement
- Under that, set the
src
ofnewDogImg
to thedogUrl
value - Under that, append the
newDogImg
element to thedogImgsDiv
element- Use
appendChild
to accomplish this
- Use
Run the project, click the "Get Dogs" button, and verify that the dog images actually appear now! Click it a few times to see some different pairs of dogs. The code in the body of the arrow function should look something like this:
let newDogImg = document.createElement("img");
newDogImg.src = dogUrl;
dogImgsDiv.appendChild(newDogImg);
Part Five: Dynamic Number of Dogs
The final step is to actually take into account the text box - this will allow the user to grab a specific number of shibes!
- Make a new line above the
let response, responseJson
line in the body of thegetDogs
function - There, create a new variable named
numDogsInput
- Set
numDogsInput
to be the<input id="num-dogs">
element- Use
document.querySelector
- Use
- Under that, create a new variable named
numDogs
- Set
numDogs
to be thevalue
of thenumDogsInput
element - Find the
fetch
call - In the
fetch
URL, replace the2
with the interpolatednumDogs
value- Use
${numDogs}
- Use
Run the project, enter a number of dogs, click the "Get Dogs" button, and verify that the proper number of dogs appears!
Conclusion
Wow. There sure are some dogs in that API! In this activity, the code used fetch
to grab data from an API (using an HTTP GET request) and display images from it.
By the end of the code-along, the script.js file should look something like this:
async function getDogs() {
let loadingImg = document.querySelector("#loading");
loadingImg.style.display = "inline-flex";
let numDogsInput = document.querySelector("#num-dogs");
let numDogs = numDogsInput.value;
let response, responseJson;
try {
response = await fetch(`https://give-me-dogs.glitch.me/dogs?count=${numDogs}`);
responseJson = await response.json();
} catch (e) {
alert(e);
return;
} finally {
loadingImg.style.display = "none";
}
let dogImgsDiv = document.querySelector("#dog-imgs");
dogImgsDiv.innerHTML = "";
responseJson.forEach(dogUrl => {
let newDogImg = document.createElement("img");
newDogImg.src = dogUrl;
dogImgsDiv.appendChild(newDogImg);
});
}
Next Steps
Click here to see how you can make more updates to the Dog Fetcher site!