frontend/javascript

🟨 2-9. fetch 완벽 가이드 — API 데이터 요청, JSON 응답 처리, 에러 핸들링까지 한 번에 배우기

mirabo01 2025. 11. 7. 08:50

 


1. fetch란 무엇인가

fetch()는 자바스크립트 내장 함수로,
서버와 HTTP 요청(Request)응답(Response) 을 주고받을 때 사용한다.
쉽게 말하면 브라우저 안에서 API를 호출하는 기본 도구다.

fetch("https://jsonplaceholder.typicode.com/posts");

이 한 줄로 브라우저는 서버에 요청을 보내고,
응답을 Promise 형태로 반환한다.


2. fetch 기본 구조

fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then((response) => response.json()) // JSON 변환
  .then((data) => console.log(data))
  .catch((error) => console.error("에러:", error));

✅ fetch()는 항상 Promise를 반환한다.
✅ response.json() 도 Promise이기 때문에 또 한 번 then으로 이어진다.
✅ catch()로 네트워크 실패나 파싱 오류를 처리한다.


3. async/await로 더 깔끔하게

async function getPost() {
  try {
    const res = await fetch("https://jsonplaceholder.typicode.com/posts/1");
    if (!res.ok) throw new Error("HTTP 오류 발생: " + res.status);
    const data = await res.json();
    console.log("✅ 데이터:", data);
  } catch (error) {
    console.error("❌ 오류:", error.message);
  }
}

getPost();

✅ res.ok는 HTTP 상태 코드가 200~299일 때 true다.
✅ 비정상 응답(예: 404, 500)은 명시적으로 예외를 던져야 한다.
✅ try-catch 구문으로 안정적인 에러 처리가 가능하다.


4. GET 요청 — 데이터 불러오기

실제 목록 데이터를 화면에 렌더링하는 예시다.

게시글 목록

    
    async function loadPosts() {
      const list = document.getElementById("postList");
      try {
        const res = await fetch("<a href=https://jsonplaceholder.typicode.com/posts?_limit=5>https://jsonplaceholder.typicode.com/posts?_limit=5</a>");
        const posts = await res.json();
        posts.forEach((post) => {
          const li = document.createElement("li");
          li.innerHTML = `<strong>${post.title}</strong><p>${post.body}</p>`;
          list.appendChild(li);
        });
      } catch (err) {
        list.innerHTML = `<li style="color:red;">데이터를 불러오는 중 오류가 발생했습니다.</li>`;
      }
    }
    loadPosts();
    

    ✅ fetch → JSON 변환 → DOM 추가 까지가 가장 흔한 패턴.
    ✅ API 호출 실패 시 사용자에게 시각적 피드백 제공.


    5. POST 요청 — 데이터 전송하기

    fetch()를 사용해 데이터를 서버로 보낼 수도 있다.
    이때는 method, headers, body 속성을 지정해야 한다.

    async function createPost() {
      const newPost = {
        title: "새로운 글",
        body: "이건 자바스크립트 fetch로 보낸 게시글입니다.",
        userId: 1,
      };
    
      try {
        const res = await fetch("https://jsonplaceholder.typicode.com/posts", {
          method: "POST",
          headers: {
            "Content-Type": "application/json", // JSON 전송 명시
          },
          body: JSON.stringify(newPost),
        });
    
        const data = await res.json();
        console.log("서버 응답:", data);
      } catch (error) {
        console.error("전송 오류:", error);
      }
    }
    
    createPost();
    

    ✅ body는 반드시 문자열이어야 하므로 JSON.stringify() 필요.
    ✅ 서버 응답은 다시 JSON으로 변환해 사용.


    6. PUT / PATCH / DELETE 요청

    메서드 역할

    PUT 데이터 전체 수정
    PATCH 일부 수정
    DELETE 데이터 삭제
    // 게시글 수정 (PATCH)
    async function updatePost() {
      await fetch("https://jsonplaceholder.typicode.com/posts/1", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ title: "수정된 제목" }),
      });
    }
    
    // 게시글 삭제
    async function deletePost() {
      await fetch("https://jsonplaceholder.typicode.com/posts/1", { method: "DELETE" });
    }
    

    ✅ RESTful API의 핵심 동작 방식이다.
    ✅ 실제 서버 연동 시, 이러한 요청 메서드를 정확히 이해해야 한다.


    7. fetch의 옵션 요약

    fetch(url, {
      method: "GET",              // 요청 방식
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data), // POST, PUT일 때만 사용
      credentials: "include",     // 쿠키 포함 (CORS 설정 필요)
    });
    

    ✅ credentials: "include" → 인증이 필요한 API에서 쿠키 자동 전송
    ✅ mode: "cors" → 도메인이 다른 서버로 요청할 때 필요


    8. 에러 핸들링 패턴

    네트워크 에러나 서버 오류를 처리하는 3단계 패턴이다.

    async function fetchData(url) {
      try {
        const res = await fetch(url);
        if (!res.ok) throw new Error(`HTTP 오류: ${res.status}`);
        return await res.json();
      } catch (error) {
        console.error("API 요청 실패:", error.message);
        return null;
      }
    }
    
    (async () => {
      const data = await fetchData("https://jsonplaceholder.typicode.com/posts/999999");
      if (!data) {
        alert("데이터를 불러올 수 없습니다.");
      }
    })();
    

    ✅ 사용자에게 오류를 표시하는 UX까지 포함해야 진짜 “실무형 코드”다.


    9. 병렬 요청 — Promise.all

    여러 API를 동시에 불러와야 할 때 Promise.all()로 병렬 처리 가능.

    async function loadAll() {
      const [users, posts] = await Promise.all([
        fetch("https://jsonplaceholder.typicode.com/users").then((r) => r.json()),
        fetch("https://jsonplaceholder.typicode.com/posts").then((r) => r.json()),
      ]);
      console.log("유저 수:", users.length, "게시글 수:", posts.length);
    }
    
    loadAll();
    

    ✅ 각각 따로 기다리지 않아도 되어 속도가 빨라진다.


    10. 실제 프로젝트에서의 fetch 사용 예시

    기능 예시

    로그인 요청 POST /auth/login
    회원 정보 조회 GET /user/me
    게시글 작성 POST /posts
    좋아요 처리 PATCH /posts/:id/like
    로그아웃 DELETE /auth/session

    이런 API 호출들은 전부 fetch() 기반으로 구성된다.
    나중에 Axios를 배우더라도 내부적으로는 같은 원리다.


    11. 자주 하는 실수 정리

    실수 올바른 방법

    JSON 안에서 따옴표 누락 항상 "키": "값" 형태로
    body에 객체 직접 전달 반드시 JSON.stringify() 사용
    응답을 바로 출력 .json() 또는 .text()로 파싱
    CORS 오류 서버 또는 프록시에서 헤더 설정 필요

    12. 정리

    개념 설명

    fetch 브라우저의 HTTP 요청 함수
    Promise 기반 비동기 처리에 사용
    JSON 응답 .json() 으로 파싱
    method GET, POST, PUT, DELETE
    에러 처리 try-catch 또는 res.ok 체크

    13. 마무리

    이제 당신은 자바스크립트에서 서버와 데이터를 주고받는 모든 과정을 완벽히 이해했다.
    fetch는 단순한 함수가 아니라,
    웹앱이 세상과 소통하게 만드는 데이터 파이프라인의 출발점이다.

    데이터를 잘 다루는 개발자는 결국 네트워크를 이해하는 개발자다.