JavaScriptJavaScript 기초 · 8중급

fetch API — 외부 데이터 가져오기

JavaScriptfetchAPIasyncawait비동기

"서버에서 데이터를 가져오고 싶어요"

날씨 앱은 기상청 서버에서 날씨 데이터를 받아옵니다. 유튜브는 서버에서 영상 목록을 받아옵니다. 이처럼 외부 서버에서 데이터를 가져오는 것이 API 호출이고, 브라우저에서는 fetch를 사용합니다.


비동기(Async)란?

// 동기 코드: 위에서 아래로 순서대로 실행
console.log("1");
console.log("2");
console.log("3");
// 출력: 1, 2, 3

네트워크 요청은 시간이 걸립니다. 기다리는 동안 다른 코드가 멈추면 페이지가 얼어버립니다. 그래서 비동기로 처리합니다 — 요청을 보내놓고, 응답이 오면 그때 처리합니다.


fetch 기본 사용법

fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then(response => response.json())   // 응답을 JSON으로 변환
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error("오류 발생:", error);
  });

async/await — 더 읽기 쉬운 방법

.then() 체이닝 대신 동기 코드처럼 읽히는 방법입니다.

async function getData() {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error("오류 발생:", error);
  }
}

getData();
  • async: 비동기 함수임을 선언
  • await: 결과가 올 때까지 기다림 (async 함수 안에서만 사용 가능)
  • try/catch: 오류 처리

공개 API 활용 — 포켓몬

async function getPokemon(name) {
  try {
    const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${name}`);

    if (!response.ok) {
      throw new Error("포켓몬을 찾을 수 없습니다.");
    }

    const data = await response.json();

    return {
      name: data.name,
      image: data.sprites.front_default,
      height: data.height,
      weight: data.weight,
    };
  } catch (error) {
    console.error(error.message);
    return null;
  }
}

// 사용
getPokemon("pikachu").then(pokemon => {
  if (pokemon) {
    console.log(`이름: ${pokemon.name}`);
    console.log(`키: ${pokemon.height * 10}cm`);
  }
});

실전 예제: 포켓몬 카드 앱

<input type="text" id="pokemon-input" placeholder="포켓몬 이름 (영문)" />
<button id="search-btn">검색</button>
<div id="pokemon-card"></div>
const card = document.querySelector("#pokemon-card");

async function showPokemon(name) {
  card.innerHTML = "<p>불러오는 중...</p>";

  try {
    const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${name.toLowerCase()}`);

    if (!res.ok) throw new Error("찾을 수 없음");

    const data = await res.json();

    card.innerHTML = `
      <div style="border:1px solid #ddd; border-radius:12px; padding:20px; text-align:center; max-width:200px;">
        <img src="${data.sprites.front_default}" alt="${data.name}" width="120" />
        <h2>${data.name.toUpperCase()}</h2>
        <p>키: ${data.height * 10}cm | 몸무게: ${data.weight / 10}kg</p>
        <p>타입: ${data.types.map(t => t.type.name).join(", ")}</p>
      </div>
    `;
  } catch (err) {
    card.innerHTML = `<p style="color:red">포켓몬을 찾을 수 없습니다.</p>`;
  }
}

document.querySelector("#search-btn").addEventListener("click", () => {
  const name = document.querySelector("#pokemon-input").value.trim();
  if (name) showPokemon(name);
});

로딩 상태 처리

사용자 경험을 위해 로딩 중임을 알려줘야 합니다.

async function fetchData(url) {
  const loading = document.querySelector("#loading");
  const content = document.querySelector("#content");

  loading.style.display = "block";
  content.style.display = "none";

  try {
    const res = await fetch(url);
    const data = await res.json();

    content.innerHTML = `<p>${data.title}</p>`;
    content.style.display = "block";
  } catch (err) {
    content.innerHTML = `<p>오류가 발생했습니다.</p>`;
    content.style.display = "block";
  } finally {
    loading.style.display = "none";
  }
}

finally 블록은 성공/실패 상관없이 항상 실행됩니다.


무료 공개 API 모음

APIURL제공 데이터
JSONPlaceholderjsonplaceholder.typicode.com테스트용 데이터
PokéAPIpokeapi.co포켓몬 데이터
Open-Meteoopen-meteo.com날씨 (무료, 키 불필요)
Cat Factscatfact.ninja고양이 사실

직접 해보기 ✏️

JSONPlaceholder API를 사용해 보세요.

// 할 일 목록 가져오기 (처음 10개)
async function loadTodos() {
  const res = await fetch("https://jsonplaceholder.typicode.com/todos?_limit=10");
  const todos = await res.json();

  // todos 배열을 화면에 렌더링하세요
  const list = document.querySelector("#todo-list");
  list.innerHTML = todos
    .map(todo => `<li>${todo.completed ? "✅" : "⬜"} ${todo.title}</li>`)
    .join("");
}

loadTodos();

정리

개념내용
fetch(url)외부 URL에 요청
.json()응답을 JSON으로 변환
async function비동기 함수 선언
await결과 기다리기
try/catch오류 처리

다음 편에서는 JavaScript의 핵심 개념인 클래스와 모듈 — 코드를 구조적으로 나누는 방법을 배웁니다.

궁금한 점이 있으신가요?

협업·의뢰는 아래로, 가벼운 소통은 인스타그램 @bluefox._.hi도 환영이에요.