날씨, 뉴스, 가격 정보를 외부에서 가져오고 싶다면 fetch가 필요해요. async/await, 에러 처리, 로딩 상태까지 — 실제 공개 API로 바로 체험해봐요.
JavaScript는 기본적으로 한 줄씩 순서대로 실행돼요(동기). 그런데 서버에서 데이터를 가져오는 건 시간이 걸리기 때문에 기다리는 동안 다른 작업을 할 수 있어야 해요(비동기). async/await는 비동기 코드를 동기 코드처럼 읽기 쉽게 써주는 문법이에요.
fetch 흐름: 브라우저 → API 서버에 요청 → 서버가 JSON 응답 → response.json()으로 파싱 → 데이터 사용. 이 모든 단계가 비동기이기 때문에 await으로 기다려야 해요.
URL에 HTTP 요청을 보내요. Promise를 반환하므로 await으로 결과를 기다려야 해요. 기본값은 GET 요청이고, 두 번째 인자로 옵션을 넣으면 POST 등 다른 메서드도 사용할 수 있어요.
서버 응답 본문을 JSON으로 파싱해요. 이것도 비동기라 await이 필요해요. response.text()는 텍스트, response.blob()은 이미지/파일을 받을 때 사용해요.
함수 앞에 async를 붙이면 그 함수 안에서 await을 쓸 수 있어요. await은 Promise가 완료될 때까지 코드 실행을 잠시 멈춰요. 동기 코드처럼 읽히지만 실제론 비동기예요.
네트워크 에러, 타임아웃, API 서버 오류 등 예외를 잡아요. response.ok가 false면 HTTP 4xx/5xx 에러예요. fetch 자체는 에러를 던지지 않기 때문에 if (!response.ok) 체크가 꼭 필요해요.
| 방식 | 읽기 난이도 | 에러 처리 | 권장도 |
|---|---|---|---|
| 콜백 (구식) | 콜백 지옥 | 번거로움 | 지양 |
| .then().catch() (Promise) | 중간 | 가능 | 보통 |
| async / await (현재 표준) | 동기 코드처럼 | try/catch | ✅ 권장 |
이 패턴들을 조합하면 대부분의 API 연동 시나리오를 처리할 수 있어요.
날씨, 게시글 목록, 환율 등 서버에서 데이터를 읽을 때 사용해요. 기본 fetch는 자동으로 GET 요청이에요. URL에 쿼리스트링(?key=value)으로 파라미터를 전달해요.
회원가입, 댓글 작성, 주문처럼 서버에 새 데이터를 생성할 때 사용해요. method: 'POST', headers, body를 옵션으로 넣어요. body는 JSON.stringify()로 직렬화해야 해요.
요청 중에는 스피너나 "로딩 중..." 메시지를 보여주고, 완료되면 숨겨요. 버튼을 비활성화해서 중복 요청을 막는 것도 중요해요. UX에서 가장 많이 놓치는 부분이에요.
네트워크 단절, API 키 오류(401), 찾을 수 없음(404), 서버 오류(500) 등을 각각 처리해요. 사용자에게 친절한 메시지를 보여주는 게 중요해요. 에러를 그냥 콘솔에만 출력하면 사용자는 왜 안 되는지 모릅니다.
가장 많이 쓰이는 패턴을 템플릿으로 정리했어요. 복사해서 AI에게 "우리 프로젝트에 맞게 수정해줘"라고 하면 돼요.
가장 많이 쓰이는 표준 패턴이에요. 이 구조를 외워두세요.
// async 함수 안에서만 await 사용 가능 async function getData(url) { try { // 1. 요청 보내기 const response = await fetch(url); // 2. HTTP 에러 체크 (fetch는 4xx/5xx에서 에러 안 던짐!) if (!response.ok) { throw new Error(`HTTP 에러: ${response.status}`); } // 3. JSON 파싱 const data = await response.json(); // 4. 데이터 활용 console.log(data); return data; } catch (err) { // 5. 에러 처리 console.error('데이터 로드 실패:', err.message); throw err; // 호출한 곳으로 에러 전달 } } // 호출 getData('https://api.example.com/posts');
실제 서비스에서 꼭 필요한 로딩·성공·에러 세 가지 상태 처리 패턴이에요.
async function loadPosts() { const btn = document.getElementById('load-btn'); const result = document.getElementById('result'); const status = document.getElementById('status'); // 로딩 시작 btn.disabled = true; status.textContent = '⏳ 로딩 중...'; result.innerHTML = ''; try { const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5'); if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); const data = await res.json(); // 성공: 카드 렌더링 status.textContent = `✅ 게시글 ${data.length}개 로드 완료`; result.innerHTML = data.map(post => ` <div class="post-card"> <strong>${post.title}</strong> <p>${post.body.substring(0, 80)}...</p> </div> `).join(''); } catch (err) { // 에러: 사용자에게 표시 status.textContent = `❌ 오류: ${err.message}`; } finally { btn.disabled = false; // 항상 버튼 복구 } }
폼 제출, 댓글 저장, 로그인 등 서버로 데이터를 전송할 때 쓰는 패턴이에요.
async function postData(url, body) { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body), // 객체 → JSON 문자열 변환 }); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); } // 사용 예시 postData('https://jsonplaceholder.typicode.com/posts', { title: '새 게시글', body: '내용입니다.', userId: 1, }).then(data => { console.log('저장 완료:', data); });
CORS 에러가 나요! 다른 도메인의 API를 브라우저에서 직접 호출하면 CORS(Cross-Origin Resource Sharing) 에러가 발생할 수 있어요. 서버 측에서 Access-Control-Allow-Origin 헤더를 허용해야 해요. 공개 API를 테스트할 때는 CORS를 허용한 API를 찾거나, Netlify Functions / Vercel Edge Functions 같은 중간 서버를 거쳐야 해요.
아래 데모는 실제 공개 API(JSONPlaceholder)를 호출해요. 버튼을 눌러 데이터가 불러와지는 걸 직접 확인해보세요.
API 연동을 AI에게 맡길 때 구체적으로 요청할수록 완성도 높은 코드를 받을 수 있어요.
아래 프롬프트를 Claude, ChatGPT, Cursor에 복사해서 바로 사용해보세요.
내 HTML 페이지에서 외부 API 데이터를 가져와서 카드로 표시하는 기능을 만들어줘. API 정보: - URL: https://api.example.com/products - 메서드: GET - 응답 형태: JSON 배열, 각 항목에 name, price, image 필드 있음 요구사항: - async/await 패턴 사용 - 로딩 중 스피너 표시, 완료 후 숨기기 - HTTP 에러(4xx, 5xx)와 네트워크 에러 모두 처리 - 에러 시 사용자에게 친절한 메시지 표시 - 각 제품을 카드 형태로 렌더링 (이름, 가격, 이미지) - 버튼 클릭 시 중복 요청 방지 순수 HTML + Vanilla JS로 구현해줘.
팁: 사용할 API의 실제 응답 JSON을 복사해서 "응답 예시는 이렇게 생겼어:"라고 함께 붙여주면 AI가 정확한 필드명으로 코드를 작성해줘요.
fetch와 비동기를 처음 배울 때 맞닥뜨리는 질문들이에요.
response.ok (status 200~299이면 true)를 직접 체크하고 수동으로 에러를 throw해야 해요.
const data = fetch(url)처럼 await 없이 쓰면 data는 실제 데이터가 아니라 Promise 객체예요. data.title을 출력하면 undefined가 나오는 게 흔한 실수예요. 비동기 작업이 있는 곳마다 await을 붙여야 해요.
Promise.all([fetch(url1), fetch(url2)])을 사용하면 두 요청을 동시에 보내고 둘 다 완료될 때까지 기다려요. 순서대로 기다리는 것보다 훨씬 빠릅니다. 하나라도 실패하면 전체가 reject되므로 주의하세요. 개별 에러 처리가 필요하면 Promise.allSettled를 사용해요.