챕터 4.3: POST/PUT/DELETE 요청 보내기
학습 시간: 1시간
1. 능동형 명령어: 실행부터 폐기까지
지금까지 우리 통제 센터는 정보만 요청했습니다(GET
). 이제 능동형 명령어를 보내는 방법을 배울 것입니다:
- POST: "새 위성을 궤도에 발사하라!"
- PUT: "ISS 시스템을 전면 현대화하라!"
- DELETE: "오래된 장치
Debris-123
을 궤도에서 이탈시켜라!"
이를 위해 fetch
를 사용하지만, 이번에는 명령어를 설명하는 추가 매개변수와 함께 사용합니다.
💡 우주 비유:
GET
이 라디오 방송을 수동적으로 청취하는 것이라면,POST
,PUT
,DELETE
는 능동적으로 명령어를 전송하는 것입니다. 이를 위해서는 "주파수"(URL)뿐만 아니라 명령어의 내용(요청 본문)과 통신 프로토콜(헤더)도 지정해야 합니다.
2. POST 요청 보내기: 새 우주선 발사
새 리소스를 생성하려면 POST
요청을 보냅니다. 여기서 가장 중요한 것은 새 객체의 데이터를 담은 요청의 본문(body)을 전달하는 것입니다.
1단계: index.html
에 생성 폼 추가
"ID로 요청" 블록 뒤에 배치합니다.
<!-- index.html -->
<hr>
<h2>새 장치 발사</h2>
<form id="create-ship-form">
<input type="text" id="create-name" placeholder="이름" required><br>
<input type="text" id="create-type" placeholder="유형" required><br>
<input type="number" id="create-year" placeholder="발사 연도" required><br>
<input type="text" id="create-status" placeholder="상태" required><br>
<button type="submit">발사</button>
</form>
<div id="create-status-message"></div>
2단계: app.js
에 로직 추가
// app.js, 파일 끝 부분
const createShipForm = document.getElementById('create-ship-form');
const createStatusMessage = document.getElementById('create-status-message');
async function createShip(event) {
event.preventDefault();
// 1. 폼의 데이터를 객체로 수집
const shipData = {
name: document.getElementById('create-name').value,
type: document.getElementById('create-type').value,
launch_year: parseInt(document.getElementById('create-year').value),
status: document.getElementById('create-status').value
};
try {
createStatusMessage.textContent = '발사 명령 전송 중...';
// 2. 매개변수와 함께 fetch 요청 보내기
const response = await fetch(`${API_BASE_URL}/spaceships`, {
method: 'POST', // 메소드 지정
headers: {
'Content-Type': 'application/json' // JSON을 보낸다고 서버에 알림
},
body: JSON.stringify(shipData) // JavaScript 객체를 JSON 문자열로 변환
});
if (!response.ok) {
// 서버가 오류를 반환한 경우, 본문을 읽으려고 시도
const errorData = await response.json();
throw new Error(errorData.detail || `서버 오류: ${response.status}`);
}
const newShip = await response.json();
createStatusMessage.textContent = `🚀 성공적인 발사! 장치에 ID가 할당되었습니다: ${newShip.id}`;
createShipForm.reset(); // 폼 초기화
fetchAndDisplayFleet(); // 전체 함대 목록 업데이트
} catch (error) {
console.error('장치 발사 오류:', error);
createStatusMessage.textContent = `🔴 오류: ${error.message}`;
}
}
createShipForm.addEventListener('submit', createShip);
fetch
의 주요 포인트:
method: 'POST'
: HTTP 메소드를 반드시 지정합니다.headers: { 'Content-Type': 'application/json' }
: 매우 중요한 헤더입니다. 요청 본문에 JSON이 포함되어 있으며 이를 파싱해야 한다고 FastAPI 서버에 알려줍니다.body: JSON.stringify(shipData)
: JavaScript 객체를 직접 보낼 수 없습니다. JSON 문자열로 직렬화(변환)해야 합니다.
3. DELETE 요청 보내기: 장치 폐기
삭제 요청은 더 간단합니다. 일반적으로 본문이 필요 없으며, 객체의 ID가 포함된 URL만 있으면 됩니다.
1단계: 우리 우주선 목록에 "삭제" 버튼 추가
app.js
의 fetchAndDisplayFleet
함수를 수정하여 각 항목에 삭제 버튼을 추가하도록 합니다.
// app.js, fetchAndDisplayFleet 함수 내부
// ...
ships.forEach(ship => {
const listItem = document.createElement('li');
// ID를 저장하는 data-속성을 가진 버튼 추가
listItem.innerHTML = `
<strong>${ship.name} (ID: ${ship.id})</strong><br>
유형: ${ship.type} | 연도: ${ship.launch_year} | 상태: ${ship.status}<br>
<button class="delete-btn" data-ship-id="${ship.id}">장치 폐기</button>
`;
fleetList.appendChild(listItem);
});
// ...
2단계: 모든 "삭제" 버튼에 대한 핸들러 추가 우리는 이벤트 위임을 사용합니다. 즉, 전체 목록에 하나의 핸들러를 사용합니다.
// app.js, 파일 끝 부분
async function deleteShip(shipId) {
if (!confirm(`ID ${shipId}를 가진 장치를 폐기하시겠습니까? 이 작업은 되돌릴 수 없습니다.`)) {
return;
}
try {
const response = await fetch(`${API_BASE_URL}/spaceships/${shipId}`, {
method: 'DELETE' // 메소드 지정
});
if (!response.ok) {
throw new Error(`장치를 폐기하지 못했습니다. 상태: ${response.status}`);
}
alert(`ID ${shipId}를 가진 장치가 성공적으로 폐기되었습니다.`);
fetchAndDisplayFleet(); // 목록 업데이트
} catch (error) {
console.error('폐기 중 오류:', error);
alert(`오류: ${error.message}`);
}
}
// 이벤트 위임: 전체 목록의 클릭을 수신
fleetList.addEventListener('click', (event) => {
// 'delete-btn' 클래스를 가진 버튼을 클릭했는지 확인
if (event.target.classList.contains('delete-btn')) {
const shipId = event.target.dataset.shipId; // data-속성에서 ID 가져오기
deleteShip(shipId);
}
});
3단계: Spaceship 모델에 ID 추가
main.py
파일의 모델 및 DB에 ID 추가
class Spaceship(BaseModel):
id: int
# 모델의 나머지 코드...
db_spaceships = {
1: {
"id": 1,
# 요소 1의 데이터
},
2: {
"id": 2,
# 요소 2의 데이터
},
3: {
"id": 3,
# 요소 3의 데이터
}
}
method: 'DELETE'
: 메소드를 지정합니다. 여기서는 본문과 헤더가 필요 없습니다.confirm()
: 실수로 중요한 것을 삭제하지 않도록 하는 간단한 내장 확인 창입니다.
4. PUT 요청 보내기 (자율 과제)
업데이트를 위한 PUT
요청 구현은 POST
와 매우 유사합니다.
다음 미션을 수락하시겠다면:
- 각 우주선에 "삭제" 버튼 옆에 "수정" 버튼을 추가합니다.
- "수정"을 클릭하면 폼(생성용으로 사용한 폼을 재사용 가능)을 현재 우주선 데이터로 채웁니다.
- "발사" 버튼의 텍스트를 "업데이트"로 변경합니다.
- 폼을 제출할 때,
/spaceships/{id}
로 객체의 전체 본문과 함께PUT
요청을 보냅니다. - 성공적으로 업데이트된 후에는 함대 목록을 업데이트합니다.
힌트:
POST
요청과 마찬가지로method: 'PUT'
,Content-Type
헤더,JSON.stringify()
를 포함하는body
와 함께fetch
가 필요할 것입니다.
복습 퀴즈
🚀 장 요약:
당신의 미션 통제 센터는 이제 함대를 관리할 수 있는 모든 명령을 갖추었습니다!
- ✅ 새로운 리소스를 생성하기 위해 본문과 헤더를 포함한
POST
요청을 보내는 방법을 배웠습니다. - ✅ 오래된 장치를 폐기하기 위해
DELETE
요청을 구현했습니다. - ✅
PUT
요청 구현 과제를 받아 지식을 확고히 했습니다.
완벽한 통제가 확립되었습니다! 하지만 연결이 끊기거나 서버에서 오류를 보고하면 어떻게 해야 할까요? 다음 장에서는 프런트엔드에서 중앙 집중식 오류 처리 시스템을 구축할 것입니다.
📌 확인:
- 새로운 함선 생성 양식이 작동하고 성공적으로 생성된 후 페이지의 목록이 업데이트되는지 확인하십시오.
- "장치 폐기" 버튼이 작동하고, 확인을 요청하며, 목록에서 함선을 삭제하는지 확인하십시오.
- 유효하지 않은 데이터(예: 매우 짧은 이름)로 함선을 생성해보고 FastAPI 서버가 반환하는 오류를 확인하십시오.
⚠️ 오류 발생 시:
- 서버로부터의
422
오류: 아마도 전송하는 데이터가 Pydantic 유효성 검사를 통과하지 못했을 것입니다. 브라우저 콘솔을 확인하십시오 —errorData.detail
이 어떤 필드에 문제가 있는지 보여줄 것입니다.415 Unsupported Media Type
오류:'Content-Type': 'application/json'
헤더를 추가하는 것을 잊었을 수 있습니다.- 삭제 버튼이 작동하지 않음: 이벤트 위임이 올바르게 작동하고
data-ship-id
에서shipId
를 올바르게 가져오는지 확인하십시오.