← JavaScript 강의 목록으로
🌐
브라우저 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.jsGET 요청과 JSON 파싱
02_post_json.jsPOST로 JSON 전송
03_error_handling.jsres.ok / try-catch
04_async_await.jsasync/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);
  }
})();

자주 하는 실수

  1. `res.json()` 호출을 잊고 응답 객체 자체를 사용하기.
  2. 4xx 응답을 성공으로 오인 — `res.ok` 확인 누락.
  3. POST에서 `Content-Type` 헤더를 빼먹기.
  4. `body`에 객체를 그대로 넘기기 (반드시 `JSON.stringify`).
  5. `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_저장소/)

예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗