4.2장: GET 요청 전송
학습 시간: 45분
1. GET: 우주 함대 원격 측정 요청
GET 요청은 데이터를 가져오기 위한 기본 명령어입니다. 우리 통제 센터에서는 이는 "함대 통제 센터, 상황을 보고하라!"라는 요청과 같습니다.
FastAPI 서버에 두 가지 유형의 GET 요청을 보내기 위해 fetch
를 사용할 것입니다:
- 전체 컬렉션 가져오기: "내 모든 함대를 보여줘".
- 단일 리소스 가져오기: "ID 2번 함선에 대한 자세한 정보를 줘".
💡 우주 비유:
GET /spaceships
는 모든 함대에 호출 부호를 보고하도록 요청하는 광역 요청입니다.
GET /spaceships/3
은 특정 함선(ISS)에 시스템에 대한 전체 데이터를 전송하도록 요청하는 주소 지정 요청입니다.
2. CORS 문제: "행성 간 간섭"
요청을 보내기 전에 한 가지 중요한 문제를 해결해야 합니다. 기본적으로 브라우저는 보안상의 이유로 한 "도메인"(file:///...
또는 http://localhost:5500
)에서 로드된 웹 페이지(우리의 통제 센터)가 다른 "도메인"(http://127.0.0.1:8000
)의 API로 요청을 보내는 것을 금지합니다.
이 정책을 CORS(교차 출처 리소스 공유)라고 합니다.
프론트엔드가 백엔드와 통신할 수 있도록 하려면 FastAPI 서버가 브라우저에게 "괜찮아, 이 주소에서의 요청을 신뢰해"라고 말하도록 구성해야 합니다.
1단계: python-multipart
설치
미들웨어의 올바른 작동을 위해 필요합니다.
2단계: main.py
에서 CORS 설정
FastAPI 프로젝트의 main.py
파일을 열고 다음 코드를 추가하세요:
# main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware # <-- 미들웨어 임포트
# ... 나머지 코드 (모델, db_spaceships) ...
app = FastAPI(
title="Fleet Management API",
# ...
)
# --- CORS 설정 ---
# 어떤 "도메인"(origins)이 요청을 보낼 수 있는지 지정합니다.
origins = [
"http://localhost",
"http://localhost:8080",
"http://127.0.0.1:5500", # VS Code의 Live Server용 주소
"null" # 로컬 파일 file:/// 에서의 요청용
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # 지정된 origins 허용
allow_credentials=True,
allow_methods=["*"], # 모든 메서드 (GET, POST 등) 허용
allow_headers=["*"], # 모든 헤더 허용
)
# --- 아래에 엔드포인트 ---
@app.get("/")
# ...
uvicorn
을 다시 시작하세요!
3. 모든 함선 목록 가져오기
우리 함대를 표시할 인터페이스를 만들어봅시다.
1단계: index.html
업데이트
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>통제 센터 - 함대 관리</title>
<style>
body { font-family: sans-serif; }
.ship-list { list-style: none; padding: 0; }
.ship-list li { border: 1px solid #ccc; margin-bottom: 10px; padding: 15px; border-radius: 5px; }
</style>
</head>
<body>
<h1>우주 함대 제어판</h1>
<button id="load-fleet-btn">함대 데이터 요청</button>
<h2>기기 목록:</h2>
<ul id="fleet-list" class="ship-list">
<li>명령 대기 중...</li>
</ul>
<script src="app.js"></script> <!-- 외부 스크립트 연결 -->
</body>
</html>
2단계: app.js
생성
index.html
옆에 app.js
파일을 만드세요. 여기에 모든 로직을 배치할 것입니다.
// app.js
const API_BASE_URL = 'http://127.0.0.1:8000'; // 우리 FastAPI 서버의 URL
const loadFleetBtn = document.getElementById('load-fleet-btn');
const fleetList = document.getElementById('fleet-list');
// 함대 로드 및 표시 함수
async function fetchAndDisplayFleet() {
try {
fleetList.innerHTML = '<li>원격 측정 로드 중...</li>';
// /spaceships로 GET 요청 전송
const response = await fetch(`${API_BASE_URL}/spaceships`);
if (!response.ok) {
throw new Error(`네트워크 오류: ${response.status}`);
}
const ships = await response.json(); // 함선 배열 가져오기
// 목록을 지우고 데이터 표시
fleetList.innerHTML = '';
if (ships.length === 0) {
fleetList.innerHTML = '<li>등록된 기기가 없습니다.</li>';
return;
}
ships.forEach(ship => {
const listItem = document.createElement('li');
listItem.innerHTML = `
<strong>${ship.name} (ID: ${ship.id})</strong><br>
유형: ${ship.type}<br>
발사 연도: ${ship.launch_year}<br>
상태: ${ship.status}
`;
fleetList.appendChild(listItem);
});
} catch (error) {
console.error('함대 데이터를 로드하지 못했습니다:', error);
fleetList.innerHTML = `<li>오류: ${error.message}</li>`;
}
}
// 버튼에 이벤트 핸들러 추가
loadFleetBtn.addEventListener('click', fetchAndDisplayFleet);
- async/await: 우리는 프라미스 작업을 위한 새롭고 더 편리한 구문을 사용했습니다. 4.5장에서 자세히 살펴보겠습니다. 지금은
await
가 페이지를 차단하지 않고 프라미스 실행을 "기다린다"는 것만 알아두세요. try...catch
: 비동기 함수에서 오류를 처리하는 좋은 방법입니다.
3단계: 테스트
브라우저에서 index.html
을 엽니다 (VS Code의 Live Server 확장 기능을 통해 http://127.0.0.1:5500
에서 실행하는 것이 가장 좋습니다). "함대 데이터 요청" 버튼을 클릭합니다. FastAPI에서 가져온 함선 목록이 페이지에 표시되어야 합니다!
4. 단일 함선 데이터 가져오기
이제 특정 ID로 정보를 요청하는 양식을 추가해봅시다.
1단계: index.html
에 양식 추가
<!-- index.html, 목록 뒤 -->
<hr>
<h2>ID로 요청</h2>
<form id="ship-form">
<input type="number" id="ship-id-input" placeholder="기기 ID 입력" required>
<button type="submit">기기 찾기</button>
</form>
<div id="ship-details" class="ship-list"></div>
2단계: app.js
에 로직 추가
// app.js, 파일 끝에
const shipForm = document.getElementById('ship-form');
const shipIdInput = document.getElementById('ship-id-input');
const shipDetails = document.getElementById('ship-details');
async function fetchShipById(event) {
event.preventDefault(); // 페이지 새로고침 방지
const shipId = shipIdInput.value;
if (!shipId) {
alert('ID를 입력해주세요.');
return;
}
try {
shipDetails.innerHTML = '<li>기기 검색 중...</li>';
// /spaceships/{id}로 GET 요청 전송
const response = await fetch(`${API_BASE_URL}/spaceships/${shipId}`);
if (response.status === 404) {
throw new Error('해당 ID의 기기가 등록되지 않았습니다.');
}
if (!response.ok) {
throw new Error(`네트워크 오류: ${response.status}`);
}
const ship = await response.json();
shipDetails.innerHTML = `
<li>
<strong>${ship.name} (ID: ${ship.id})</strong><br>
유형: ${ship.type}<br>
발사 연도: ${ship.launch_year}<br>
상태: ${ship.status}
</li>
`;
} catch (error) {
console.error(`기기 ${shipId} 검색 오류:`, error);
shipDetails.innerHTML = `<li>오류: ${error.message}</li>`;
}
}
shipForm.addEventListener('submit', fetchShipById);
- 사용자에게 더 명확한 오류 메시지를 제공하기 위해
404
상태를 별도로 처리했습니다.
3단계: 테스트 페이지를 새로고침하고, 기존 함선의 ID(예: 1)를 입력한 다음 "기기 찾기"를 클릭합니다. 해당 데이터를 볼 수 있습니다. 존재하지 않는 ID(예: 99)를 입력해보세요. 오류 메시지가 표시될 것입니다.
복습 퀴즈
🚀 장 요약:
"지구"와 "우주" 간의 통신 채널을 성공적으로 설정하고 원격 측정을 요청하는 방법을 배웠습니다!
- 🛡️ FastAPI 서버에 CORS를 설정하여 "행성 간 간섭" 문제를 해결했습니다.
- 🛰️ 모든 우주선 목록을 가져와 표시하는 기능을 구현했습니다.
- 🔭 ID로 특정 우주선에 대한 데이터를 요청하는 인터페이스를 생성했습니다.
관제 센터가 데이터를 수신하고 있습니다! 다음 장에서는 우주선을 생성, 업데이트 및 삭제하는 명령을 전송하는 등 적극적인 조치로 넘어갈 것입니다.
📌 확인:
CORSMiddleware
가 설정된 상태로 FastAPI 서버가 실행 중인지 확인하세요.- "데이터 요청" 버튼을 클릭할 때 페이지에 우주선 목록이 나타나는지 확인하세요.
- ID로 검색하는 폼이 기존 우주선을 올바르게 찾고 존재하지 않는 우주선에 대해 오류를 보고하는지 확인하세요.
⚠️ 오류 발생 시:
- 브라우저 콘솔의 CORS 오류:
CORSMiddleware
를 추가한 후uvicorn
을 다시 시작하지 않았거나, 프런트엔드 주소(예:http://127.0.0.1:5500
)가origins
목록에 추가되지 않았을 수 있습니다.- Failed to fetch: FastAPI 서버가 실행 중이고
API_BASE_URL
에 지정된 주소로 액세스할 수 있는지 확인하세요.