21. Fetch and JSON
Fetch is the HTTP client built into the browser (and Node 18+). It returns a Promise.
What you'll learn
- 1Send HTTP requests with `fetch()`.
- 2Convert between JSON strings and JS objects.
- 3Tell network errors apart from HTTP errors.
- 4Rewrite fetch code with `async/await`.
Overview
Fetch is the HTTP client built into the browser (and Node 18+). It returns a Promise.
Core Concepts
1. What is fetch?
Fetch is the HTTP client built into the browser (and Node 18+). It returns a Promise.
fetch('https://jsonplaceholder.typicode.com/users/1')
.then((res) => res.json())
.then((user) => console.log(user.name));`res.json()` parses the response body as JSON and returns another Promise.
2. JSON.parse / JSON.stringify
JSON is a text-based data format β use these to convert to and from JS objects.
const obj = { name: 'Yi Sunshin', age: 35 };
const str = JSON.stringify(obj); // '{"name":"Yi Sunshin","age":35}'
const back = JSON.parse(str); // { name: 'Yi Sunshin', age: 35 }3. POST requests
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'hi', body: 'hello', userId: 1 }),
}).then((res) => res.json());4. Error handling
`fetch` does not reject on 4xx/5xx. You must check `res.ok` yourself.
fetch(url)
.then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.catch((err) => console.error('failed:', err));A genuine network failure does reject.
5. Rewriting with async/await
async function loadUser(id) {
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}Examples
| File | What it covers |
|---|---|
| 01_get_json.js | GET request and JSON parsing |
| 02_post_json.js | POST a JSON body |
| 03_error_handling.js | res.ok and try/catch |
| 04_async_await.js | Rewrite with async/await |
src/01_get_json.js
/**
* GET JSON data
*/
fetch('https://jsonplaceholder.typicode.com/users/1')
.then((res) => res.json())
.then((user) => {
console.log('name:', user.name);
console.log('email:', user.email);
});
src/02_post_json.js
/**
* POST a JSON body
*/
const newPost = {
title: 'hi fetch',
body: 'body content',
userId: 1,
};
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newPost),
})
.then((res) => res.json())
.then((created) => console.log('created:', created));
src/03_error_handling.js
/**
* fetch error handling: res.ok plus catch
*/
fetch('https://jsonplaceholder.typicode.com/users/9999')
.then((res) => {
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
return res.json();
})
.then((data) => console.log(data))
.catch((err) => console.error('failed:', err.message));
src/04_async_await.js
/**
* Rewritten with async/await
*/
async function loadUser(id) {
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
(async () => {
try {
const user = await loadUser(2);
console.log(user.name);
} catch (err) {
console.error(err);
}
})();
Common Mistakes
- Forgetting to call `res.json()` and using the response object directly.
- Treating a 4xx response as success β you must check `res.ok`.
- Omitting the `Content-Type` header in a POST.
- Passing an object as `body` instead of `JSON.stringify(...)`.
- Using `await` outside an `async` function.
FAQ
Q1. Does fetch work in Node?
Yes, globally since Node 18. **Q2. Should I still use XMLHttpRequest?** A. Only for legacy compatibility β new code uses fetch. **Q3. Why am I seeing CORS errors?** A. The remote server must allow your origin β this is a server-side configuration issue.
Practice
Fetch users/posts from JSONPlaceholder and render them on the page.
homework/README.md
## Homework 1 β Fetch every user from `https://jsonplaceholder.typicode.com/users` and print only the names. Use async/await.
## Homework 2 β On an HTML page, fetch one post when a button is clicked and render it.
- Endpoint: `https://jsonplaceholder.typicode.com/posts/1`
- Render with `<h2>` for title and `<p>` for body.
homework/answer/homework_01.js
/**
* Homework 1: print user names
*/
async function listUserNames() {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const users = await res.json();
users.forEach((u) => console.log(u.name));
}
listUserNames().catch((err) => console.error(err));
homework/answer/homework_02.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Homework 2 β Fetch a post</title>
</head>
<body>
<button id="load">Load post</button>
<div id="result"></div>
<script src="homework_02.js"></script>
</body>
</html>
homework/answer/homework_02.js
/**
* Homework 2: fetch a post on click
*/
document.getElementById('load').addEventListener('click', async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/posts/1');
if (!res.ok) {
alert(`HTTP ${res.status}`);
return;
}
const post = await res.json();
const box = document.getElementById('result');
box.innerHTML = '';
const h2 = document.createElement('h2');
h2.textContent = post.title;
const p = document.createElement('p');
p.textContent = post.body;
box.append(h2, p);
});
Next Lecture
[22_Storage](../22_μ μ₯μ/)
All lecture materials and example code are openly available on GitHub.
View on GitHub β