Project Walk-Through: Building a simple advice slip generator
Being able to use an API was one of my main motivations for learning how to code. I love how there is so much information out there (on *the Internet*). If I could only just get it into one place, all the successes and riches could be mine! (/s)
Being confident in reading their documentation is certainly one of the first hurdles. Knowing what to do with it… well, that quickly follows as far as hurdles go.
I thought it would be helpful to write a walk-through of the code for a short project I created, in hopes that it could help someone else who also struggled like I did. Once you begin to get the hang of it, it’s great fun! Or, if you’ve had quite a bit of experience with JavaScript and using fetch
, please do feedback by leaving a comment of what could be improved. I’ve also tried to link through directly to the documentation on MDN.
Let’s find an API
After trying out a few APIs, I began to go down the rabbit hole of CORS-related errors. That can feel like a massive set-back when I knew I only just wanted to get something to tinker with and get some practice (on the bright side, it did expose me to some of the other headers you can send, which helped me understand a bit more about what goes into requests).
I settled on the Advice Slip JSON API, which seemed to play nice when making requests directly in the console (so I could explore), directly from my javascript file, and finally, my GitHub, where you can access it and try it out for yourself.
If you’d like to follow along, you’ll need to create a HTML, JavaScript, and CSS file, but let’s try out this API in the console first, so we can see what we get back.
I started off by assigning the URL of the API to a variable. We then fetched that URL to get back a Promise object.
For what we’re trying to build, the response we get back as a Promise object on its own is of no use to us. The next piece of the puzzle, a method called .then()
lets us take that information and turn it into something we can use, which in our case, is a nicely structured piece of JSON.
I’ve used the convention of calling it response, because as you can see, if we don’t chain on .then()
, the value that we’re getting back from just calling fetch
, is just… Response
:
Compare this with the first screenshot and you can see what I’m referring to. We need that Object
containing the slip
to begin to build. Let’s carry on.
Time for our HTML file
Let’s set up our HTML file in order to render the information returned to us from the API. We’ll also use it to link our style sheet, and pull in our Google Fonts.
Within your HTML head
, you’ll need to add in:
<link href="https://fonts.googleapis.com/css?family=Abril+Fatface|Bungee|Notable|Roboto+Mono|Roboto+Slab&display=swap" rel="stylesheet"><link rel="stylesheet" href="advice.css">
I’ve chosen five different fonts. You can choose whatever (or however many!) you’d like — Google Fonts will provide you with the code you need to reference the fonts you’d like to use. But, choosing too many will slow down how quickly your page loads, so I’ve stuck with five. Below that, I’ve also provided a link to a CSS file, which we won’t go into detail here.
Within the body of the HTML file, the advice needs somewhere to go, so I’ve made an h2
with a given id
of “quote”, so it’s easy to find:
<h2 id="quote"></h2>
I’ve also made a button, to repeat the process of making another GET
request without needing to refresh the page:
<button id="reload">Give me another</button>
Finally, just before closing the body, add in the link to your lovely JavaScript:
<script type="text/javascript" src="advice.js"></script></body>
Time for some JavaScript
I’ve decided to skip over what’s within the CSS file. Although you’re welcome to have a look, there isn’t anything in there that will affect the functionality of the app, so we won’t be discussing it here. Let’s carry on.
As outlined in the console screenshots earlier, let’s first store the URL we’ll need to call fetch on, and store fetch
within its own function. Although this app is not so big that it probably couldn’t all be smushed together, it’s much easier to see what the code is doing when its separated out:
const API_URL = "https://api.adviceslip.com/advice";function get(url) {return fetch(url).then(resp => resp.json())}const API = { get }
Here we have three little lines that have stored our URL, written a fetch function, and assigned our function to an object called API.
We’ll also need some other bits and pieces to get our app up and running, so let’s declare some constants:
const fontType = ["Roboto Mono", "Roboto Slab", "Abril Fatface", "Notable", "Bungee"]const colours = ["#FFCDD2", "#FCE4EC", "#F3E5F5", "#8C9EFF", "#90CAF9", "#80D8FF", "#80DEEA", "#B2DFDB", "#69F0AE", "#AED581", "#AED581", "#FFC400", "#BCAAA4", "#90A4AE"]const quoteP = document.querySelector("h2#quote")const bground = document.querySelector("body")
I’ve created some arrays of the font names we’ll use to update via JavaScript, as well as some options for background colours (chosen from the gorgeous HTML Color Codes website). The fact that they’re entered as an array was a matter of convenience, as I want to select from them randomly. You can also see the two other nodes we’ll need to update with our JavaScript — the aforementioned h2
with the id of #quote
, plus the body of the document.
Now let’s start to build where things really get interesting:
function getQuotes() { API.get(API_URL).then(data => addQuote(data['slip']['advice']))}
The function getQuotes
is going to run the get
method in the API
object. What’s return
ed from the italicised portion of the code, as we discussed before, is a JSON
object. I want to use that JSON
in yet another function to put the quote on the page, so I’ve chained a second .then()
to do just that. This function takes in that data as an argument (I’ve even called it data
), but more specifically, just the bit of the object we want: the slip and its advice.
We’re almost there. Let’s write that addQuote
function we need:
function addQuote(quote) { quoteP.innerText = quote; let fontsNum = Math.floor(Math.random()*fontType.length); let coloursNum = Math.floor(Math.random()*colours.length); quoteP.style.fontFamily = fontType[fontsNum]; bground.style.backgroundColor = colours[coloursNum]}
Since you saw that when we called addQuote
within the previous function, we passed in an argument, so our function needs to receive that argument. Here I’ve called it quote
.
You could leave the function at just the first line — setting the h2
with the id
quote
’s innerText
to the quote returned from our get
. The remainder is purely for style. I wanted to get two random numbers, within the range of the fontType
array or the colours
array in order to access the array element.
I also knew I wanted to avoid refreshing the page. It looks like it does a weird ‘blip’ whilst all the DOM content reloads, and as I just needed a new quote (in a new font), with a new jazzy background colour, our ‘give me another’ button sends a get
request to do just that:
const reloadButton = document.querySelector("button#reload")reloadButton.addEventListener("click", ()=> getQuotes())
As before, we stored the piece of the DOM we need — the button — into a variable, so we could do something with it. I wanted an event listener, so when clicked, we could call getQuotes
, and start the process over again.
Finally, on our very last line, we kick the process off. Once the page has loaded, call getQuotes
:
document.body.onload = getQuotes
How can it be made better?
I’d love to hear if you have any further suggestions for how to make it better. What other functionality would you add? And, if had a look at the GitHub repository, how would you refactor it?
Thanks for reading!
If you liked this, please clap or leave a comment with feedback. Subscribe to my channel for writing on code, design, and lifelong learning.