"서버에서 데이터를 가져오고 싶어요"
날씨 앱은 기상청 서버에서 날씨 데이터를 받아옵니다. 유튜브는 서버에서 영상 목록을 받아옵니다. 이처럼 외부 서버에서 데이터를 가져오는 것이 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 모음
| API | URL | 제공 데이터 |
|---|---|---|
| JSONPlaceholder | jsonplaceholder.typicode.com | 테스트용 데이터 |
| PokéAPI | pokeapi.co | 포켓몬 데이터 |
| Open-Meteo | open-meteo.com | 날씨 (무료, 키 불필요) |
| Cat Facts | catfact.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의 핵심 개념인 클래스와 모듈 — 코드를 구조적으로 나누는 방법을 배웁니다.