- Published on
Attempts at Tutorials - JavaScript API Request via Fetch
- Authors
- Name
- Matt Corr
- @matacorr
So as a fun way to come up with more blog posts(or filler if your a pessimist) I thought trying to write a few basic tutorials might work. So for this exciting first episode I'll be covering how to make an API request, I'll be using the NASA Photo of the Day as the example since I think they won't complain.
So to begin with go to the NASA site here here and have a look around. Also get yourself an API key rather then using mine. The query we'll be using is this https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY
where DEMO_KEY
will be our own API key's respectively. We'll be using Fetch
to make the request.
Very Basic Version
To see the page using this code go here. The whole thing is a functional React component which Next uses as a page.
So to begin with we need to get the full response to our request, so
const response = await fetch('https://api.nasa.gov/planetary/apod?api_key=')
We're using const
since we're not actually changing the response object once we've got it so no need to use var
or let
. Plus my VS Code complained when I used var
. We're using await
since we want to get the response before we continue since we can't return an image and it's easier to have it be linear.
Next step is to get the JSON from the response object.
const photo = await response.json()
As long as everything worked and remembered to pay your internet bill you should get a JSON object like this once
{
"date": "2023-09-19",
"explanation": "Do stars always create jets as they form? No one is sure. As a gas cloud gravitationally contracts, it forms a disk that can spin too fast to continue contracting into a protostar. Theorists hypothesize that this spin can be reduced by expelling jets. This speculation coincides with known Herbig-Haro (HH) objects, young stellar objects seen to emit jets -- sometimes in spectacular fashion. Pictured is Herbig-Haro 211, a young star in formation recently imaged by the Webb Space Telescope (JWST) in infrared light and in great detail. Along with the two narrow beams of particles, red shock waves can be seen as the outflows impact existing interstellar gas. The jets of HH 221 will likely change shape as they brighten and fade over the next 100,000 years, as research into the details of star formation continues.",
"hdurl": "https://apod.nasa.gov/apod/image/2309/HH211_webb_3846.jpg",
"media_type": "image",
"service_version": "v1",
"title": "HH 211: Jets from a Forming Star",
"url": "https://apod.nasa.gov/apod/image/2309/HH211_webb_960.jpg"
}
For now we're going to ignore how to take advantage of TypeScript. For the page we need three parts of it:
- Title
- Explanation
- Url
The Title
will be used at the top of the page for the heading. The Explanation
will be used for text underneath the image, and as the img
tag alt text. The Url
is also for the img
tag to be the src
attribute..
If we want a simple area to display it in we can use some HTML like below. The {}
is how we're adding the variable parts to the HTML.
<div>
<p className="text-3xl text-center" style={{ marginBottom: '2.5rem' }}>
{photoData.title}
</p>
<img src={photoData.url} style={{ marginBottom: '2.5rem' }}></img>
<p>{photoData.explanation}</p>
</div>
The whole code is below. The useState
and useEffect
are part of React. I'm using useState
so we can have a loading message to begin with, using an alert from DaisyUI
and replace it with the real content once the API call is done. The useEffect
then lets the component update. Inside the useEffect
is the async
function called getPhoto
with the setPhotoArea
with the information from the API. The []
at the end of the useEffect
is so we don't call the NASA API continuously and exceed the amount of API calls that can be used. Something I didn't forget to do while making the page to begin with and get Error 429 Too Many Requests
after a short while. The PageSEO
on this and the advanced version are for google, and for the tab in your browser. I've included it so show the whole page component.
import { PageSEO } from '@/components/SEO'
import { useEffect, useState } from 'react'
const SimpleNasaPhoto = () => {
const [photoArea, setPhotoArea] = useState(
<div className="alert alert-info">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
className="stroke-current shrink-0 w-6 h-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<span>Now loading, please wait.</span>
</div>
)
useEffect(() => {
async function getPhoto() {
const response = await fetch(
'https://api.nasa.gov/planetary/apod?api_key=r2wfZ5FK629lmMf2OJCphFaNr6Eip88SE9s2eyId'
)
const photoData = await response.json()
setPhotoArea(
<div>
<p className="text-3xl text-center" style={{ marginBottom: '2.5rem' }}>
{photoData.title}
</p>
<img src={photoData.url} style={{ marginBottom: '2.5rem' }}></img>
<p>{photoData.explanation}</p>
</div>
)
}
getPhoto()
}, [])
return (
<>
<PageSEO
title="Simple Nasa Photo of the Day via Fetch API"
description="The example page using the Fetch API to get the NASA Photo of the day. See blog tutorial for more details."
/>
<div>{photoArea}</div>
</>
)
}
export default SimpleNasaPhoto
Advanced Version Or Maybe Over Engineered
So what could we do to make it more reliable? Putting aside it being the NASA API so the odds of it breaking soon I think are slim let's pretend we want to check the response before we do something on the page. After all if we get a 500
or 400
error we don't have anything to display. To see the page itself click here.
Before we did this:
const response = await fetch('https://api.nasa.gov/planetary/apod?api_key=')
const photoData = await response.json()
So if the API calls fails somehow, NASA says I've requested too many times, or other errors the photoData
won't be what we want. Rather then worrying too much about checking for individual error codes, we're just going to check if it's 200
which means the request worked, and if not it'll go to the else
. The else
will be a simple alert showing the response.status
and the response.statusText
so we can see what went wrong. Normally you don't want to show the end user the error and instead just state something happened or redirect to a shared error page but that doesn't help with the tutorial. Though in theory beyond reading the source of the page here or the dev tools on the page it should all work nicely.
import { PageSEO } from '@/components/SEO'
import { useEffect, useState } from 'react'
const AdvancedNasaPhoto = () => {
const [photoArea, setPhotoArea] = useState(
<div className="alert alert-info">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
className="stroke-current shrink-0 w-6 h-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<span>Now loading, please wait.</span>
</div>
)
useEffect(() => {
async function getPhoto() {
const response = await fetch(
'https://api.nasa.gov/planetary/apod?api_key=r2wfZ5FK629lmMf2OJCphFaNr6Eip88SE9s2eyId'
)
console.log(response.status)
if (response.status == 200) {
const photoData = await response.json()
setPhotoArea(
<div>
<p className="text-3xl text-center" style={{ marginBottom: '2.5rem' }}>
{photoData.title}
</p>
<img src={photoData.url} style={{ marginBottom: '2.5rem' }}></img>
<p>{photoData.explanation}</p>
</div>
)
} else {
setPhotoArea(
<div className="alert alert-info">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
className="stroke-current shrink-0 w-6 h-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<span>
The catch all response for this page. Something went wrong. The error code was
{response.status} and the text is {response.statusText}
</span>
</div>
)
}
}
getPhoto()
}, [])
return (
<>
<PageSEO
title="Advanced Nasa Photo of the Day via Fetch API"
description="The advanced example page using the Fetch API to get the NASA Photo of the day. See blog tutorial for more details."
/>
<div>{photoArea}</div>
</>
)
}
export default AdvancedNasaPhoto
What about TypeScript?
If we wanted to use TypeScript we could take the JSON from the 200
response and define it as a type
or interface.
The I
for theinterface
version is so when seeing it in the code later we know what it is. Using either can be useful for more complex examples so if we were to try and do something that might break or cause problems when the code is running, it instead can warn us in the code editor. I've not made a page though since as far as I know the browser doesn't use TypeScript and it gets converted to JavaScript so there would be nothing to see in the inspector. To get an idea of the difference between type
andinterface
click here to go to a Log Rocket blog post on the subject.
type NasaPhoto = {
date: string;
explanation: string;
hdurl: string;
media_type: string;
service_version: string;
title: string;
url: string;
}
interface INasaPhoto = {
date: string;
explanation: string;
hdurl: string;
media_type: string;
service_version: string;
title: string;
url: string;
}
Lesson Over
Hopefully this has been useful or at least not made understanding how to use Fetch more difficult. This of course only looked at GET
there are other methods an API call can use, a main one being POST
to send something to the server. That might be the topic of another tutorial. Another way to call an API is with XMLHttpRequest
which I plan on making a tutorial for.