🌐
브라우저 API
심화 · 선수: 20_비동기_기초
21. Fetch와 JSON
브라우저(그리고 Node 18+)에 내장된 HTTP 클라이언트입니다. Promise를 반환합니다.
fetchJSONAPI비동기
소요 시간
⏱ 약 1.5시간
난이도
📊 중급
선수 조건
🎯 단원 20
결과물
브라우저(그리고 Node 18+)에 내장된 HTTP 클라이언트입니다. Promise를 반환합니다.
이 강의에서 배우는 것
- 1`fetch()` API로 HTTP 요청을 보낼 수 있다.
- 2JSON 문자열과 객체를 변환할 수 있다.
- 3네트워크 오류와 HTTP 오류를 구분해 처리할 수 있다.
- 4`async/await`로 fetch 코드를 간결하게 쓸 수 있다.
소개
브라우저(그리고 Node 18+)에 내장된 HTTP 클라이언트입니다. Promise를 반환합니다.
핵심 개념
1. fetch란?
브라우저(그리고 Node 18+)에 내장된 HTTP 클라이언트입니다. Promise를 반환합니다.
javascript
fetch('https://jsonplaceholder.typicode.com/users/1')
.then((res) => res.json())
.then((user) => console.log(user.name));`res.json()`은 응답 본문을 JSON으로 파싱해 다시 Promise를 반환합니다.
2. JSON.parse / JSON.stringify
JSON은 데이터 표현 문자열입니다. JS 객체와 변환할 때 사용합니다.
javascript
const obj = { name: '이순신', age: 35 };
const str = JSON.stringify(obj); // '{"name":"이순신","age":35}'
const back = JSON.parse(str); // { name: '이순신', age: 35 }3. POST 요청
javascript
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. 에러 처리
`fetch`는 4xx/5xx를 reject하지 않습니다. `res.ok`를 직접 확인해야 합니다.
javascript
fetch(url)
.then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.catch((err) => console.error('실패:', err));네트워크 단절은 reject 됩니다.
5. async/await 재작성
javascript
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();
}핵심 예제
| 파일 | 다루는 내용 |
|---|---|
| 01_get_json.js | GET 요청과 JSON 파싱 |
| 02_post_json.js | POST로 JSON 전송 |
| 03_error_handling.js | res.ok / try-catch |
| 04_async_await.js | async/await 재작성 |
src/01_get_json.js
javascript
/**
* GET 요청으로 JSON 데이터 받기
*/
fetch('https://jsonplaceholder.typicode.com/users/1')
.then((res) => res.json())
.then((user) => {
console.log('이름:', user.name);
console.log('이메일:', user.email);
});
src/02_post_json.js
javascript
/**
* POST 요청으로 JSON 보내기
*/
const newPost = {
title: '안녕 fetch',
body: '본문 내용',
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));
src/03_error_handling.js
javascript
/**
* fetch 에러 처리: res.ok와 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('실패:', err.message));
src/04_async_await.js
javascript
/**
* 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);
}
})();
자주 하는 실수
- `res.json()` 호출을 잊고 응답 객체 자체를 사용하기.
- 4xx 응답을 성공으로 오인 — `res.ok` 확인 누락.
- POST에서 `Content-Type` 헤더를 빼먹기.
- `body`에 객체를 그대로 넘기기 (반드시 `JSON.stringify`).
- `await`를 `async` 함수 바깥에서 사용.
FAQ
Q1. fetch는 Node에서도 되나요?
Node 18부터 전역으로 사용 가능합니다. **Q2. XMLHttpRequest는 더 안 쓰나요?** A. 호환이 필요한 경우만. 신규 코드는 fetch를 씁니다. **Q3. CORS 오류는 왜?** A. 다른 출처의 서버가 허용해야 합니다. 서버 측 설정 문제입니다.
과제
JSONPlaceholder에서 사용자/게시글을 받아 화면에 표시하세요.
homework/README.md
## 과제 1 `https://jsonplaceholder.typicode.com/users` 전체 사용자를 받아 이름만 콘솔에 출력하세요. async/await 사용.
## 과제 2 HTML 페이지에서 버튼을 누르면 게시글 1개를 받아 화면에 표시하세요.
- 엔드포인트: `https://jsonplaceholder.typicode.com/posts/1`
- `<h2>` 제목, `<p>` 본문 표시.
homework/answer/homework_01.js
javascript
/**
* 과제 1: 사용자 이름 목록 출력
*/
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
html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>과제 2 — 게시글 불러오기</title>
</head>
<body>
<button id="load">게시글 불러오기</button>
<div id="result"></div>
<script src="homework_02.js"></script>
</body>
</html>
homework/answer/homework_02.js
javascript
/**
* 과제 2: 버튼 클릭 시 게시글 1개 표시
*/
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);
});
다음 단원
[22_저장소](../22_저장소/)