The Fetch API & Working with APIs
Learn what JSON is, what an API is, and how to use the Fetch API to get data from a server.
Frontend is (almost) done — now we need to connect it to a backend. The Fetch API comes to the rescue, but first we need to understand JSON.
What is JSON?
JSON stands for JavaScript Object Notation. Think of it as a universal language computers use to send data to each other over the internet — data from servers is usually received in this format.
What does JSON look like?
JSON looks almost identical to a JavaScript object, but with a few strict rules.
{
"id": 1,
"name": "Alex Johnson",
"email": "alex@example.com",
"isPremiumMember": true,
"scores": [98, 75, 88]
}
JSON rules to remember
| Rule | JavaScript Object | JSON |
|---|---|---|
| Keys | Can be unquoted (name: "Alex") |
Must be double-quoted ("name": "Alex") |
| Strings | Single or double quotes | Must use double quotes only |
| Trailing commas | Allowed | Not allowed |
| Functions | Allowed as values | Not allowed |
Converting between JSON and JS
Since JSON is just text, you need to convert it to use it in JavaScript:
JSON.parse()— converts a JSON string into a JavaScript objectJSON.stringify(object)— converts a JavaScript object into a JSON string (so you can send it over the network)
// A raw JSON string
const jsonString = '{"name": "Alex", "score": 98}';
// Convert it to a JS object so we can use it
const playerData = JSON.parse(jsonString);
console.log(playerData.name); // "Alex"
// Convert a JS object back into a JSON string
const updatedData = { name: "Alex", score: 100 };
console.log(JSON.stringify(updatedData)); // '{"name":"Alex","score":100}'
What is an API?
An API (Application Programming Interface) is like a digital waiter at a restaurant. You (the browser) place an order (a request) — the waiter (the API) takes it to the kitchen (the server), grabs your food, and brings it back to your table.
The Fetch API is a built-in browser tool that lets you make requests to servers using JavaScript.
Making your first GET request
A GET request is used to retrieve data from a server. Here’s a basic fetch request using async/await:
async function getJoke() {
try {
// 1. Fetch data from a public joke API
const response = await fetch("https://v2.jokeapi.dev/joke/Programming?type=single");
// 2. Check if the response was successful
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// 3. Convert the response into usable JSON data
const data = await response.json();
// 4. Do something with the data
console.log("Here is your joke:", data.joke);
} catch (error) {
console.error("Failed to fetch joke:", error);
}
}
getJoke();
Breaking down the fetch line
const response = await fetch("https://v2.jokeapi.dev/joke/Programming?type=single");
fetch(...)— sends the request (places the order)- the URL — where to send it (which restaurant)
await— wait here until the answer comes backresponse— what came back (the package, not opened yet)
Why two awaits?
await fetch(...)→ the package arrives (response)await response.json()→ you open the package (data)
Both take time, so both need await.
What’s actually inside a response?
response isn’t the data itself — it’s a whole object with extra information attached. The data has to be unlocked separately.
response.status— a number telling you what happenedresponse.ok—trueorfalse, based on whetherstatusis in the success range (200–299)response.json()— unpacks the actual body of the response into a JavaScript object you can use
Common status numbers:
| Status | Meaning |
|---|---|
200 |
OK — it worked |
404 |
Not found — wrong URL |
Here’s roughly what data looks like once you log it from getJoke():
{
"category": "Programming",
"type": "single",
"joke": "Why do programmers prefer dark mode? Because light attracts bugs.",
"id": 231
}
That’s why data.joke in the example works — it’s just grabbing one key from this object.
Showing the data on the page
console.log is only for you. To show the joke to the user, put it on the page:
<button id="jokeBtn">Get a joke</button>
<p id="jokeText"></p>
async function showJoke() {
try {
const response = await fetch("https://v2.jokeapi.dev/joke/Programming?type=single");
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
document.getElementById("jokeText").textContent = data.joke;
} catch (error) {
document.getElementById("jokeText").textContent = "Could not load a joke.";
}
}
document.getElementById("jokeBtn").addEventListener("click", showJoke);
Common mistakes
- Forgetting
awaitbeforefetch(...)orresponse.json()— you get a “pending” object instead of your data. - Logging
responseinstead ofdata— you see a big object, not your joke. - Not checking
response.ok— a404looks like a success. - Typos in the URL.
Try it yourself
- Use the public API
https://jsonplaceholder.typicode.com/todos/1. Write an async function calledfetchTodo()that fetches this item and logs itstitleandcompletedstatus. - Try fetching an intentionally wrong URL (e.g.
.../todos/999999). Checkresponse.okand throw an error if the request fails. - Log
response.statusfor both a working and a broken URL, and compare the two numbers you get back.
