Skip to content

챕터 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);
POST를 위한 fetch의 주요 포인트:

  • method: 'POST': HTTP 메소드를 반드시 지정합니다.
  • headers: { 'Content-Type': 'application/json' }: 매우 중요한 헤더입니다. 요청 본문에 JSON이 포함되어 있으며 이를 파싱해야 한다고 FastAPI 서버에 알려줍니다.
  • body: JSON.stringify(shipData): JavaScript 객체를 직접 보낼 수 없습니다. JSON 문자열로 직렬화(변환)해야 합니다.

3. DELETE 요청 보내기: 장치 폐기

삭제 요청은 더 간단합니다. 일반적으로 본문이 필요 없으며, 객체의 ID가 포함된 URL만 있으면 됩니다.

1단계: 우리 우주선 목록에 "삭제" 버튼 추가 app.jsfetchAndDisplayFleet 함수를 수정하여 각 항목에 삭제 버튼을 추가하도록 합니다.

// 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와 매우 유사합니다.

다음 미션을 수락하시겠다면:

  1. 각 우주선에 "삭제" 버튼 옆에 "수정" 버튼을 추가합니다.
  2. "수정"을 클릭하면 폼(생성용으로 사용한 폼을 재사용 가능)을 현재 우주선 데이터로 채웁니다.
  3. "발사" 버튼의 텍스트를 "업데이트"로 변경합니다.
  4. 폼을 제출할 때, /spaceships/{id}로 객체의 전체 본문과 함께 PUT 요청을 보냅니다.
  5. 성공적으로 업데이트된 후에는 함대 목록을 업데이트합니다.

힌트: POST 요청과 마찬가지로 method: 'PUT', Content-Type 헤더, JSON.stringify()를 포함하는 body와 함께 fetch가 필요할 것입니다.


복습 퀴즈

1. `fetch`에서 요청 본문에 데이터를 전송하는 데 사용되는 매개변수는 무엇입니까?

2. `'Content-Type': 'application/json'` 헤더는 서버에 다음을 알립니다...

3. JavaScript의 `JSON.stringify(obj)` 함수는 무엇을 합니까?

4. `fetch`를 사용하여 `DELETE` 요청을 보내려면 다음을 반드시 지정해야 합니다.

5. JavaScript에서 이벤트 위임이란...


🚀 장 요약:

당신의 미션 통제 센터는 이제 함대를 관리할 수 있는 모든 명령을 갖추었습니다!

  • ✅ 새로운 리소스를 생성하기 위해 본문과 헤더를 포함한 POST 요청을 보내는 방법을 배웠습니다.
  • ✅ 오래된 장치를 폐기하기 위해 DELETE 요청을 구현했습니다.
  • PUT 요청 구현 과제를 받아 지식을 확고히 했습니다.

완벽한 통제가 확립되었습니다! 하지만 연결이 끊기거나 서버에서 오류를 보고하면 어떻게 해야 할까요? 다음 장에서는 프런트엔드에서 중앙 집중식 오류 처리 시스템을 구축할 것입니다.

📌 확인:

  • 새로운 함선 생성 양식이 작동하고 성공적으로 생성된 후 페이지의 목록이 업데이트되는지 확인하십시오.
  • "장치 폐기" 버튼이 작동하고, 확인을 요청하며, 목록에서 함선을 삭제하는지 확인하십시오.
  • 유효하지 않은 데이터(예: 매우 짧은 이름)로 함선을 생성해보고 FastAPI 서버가 반환하는 오류를 확인하십시오.

⚠️ 오류 발생 시:

  • 서버로부터의 422 오류: 아마도 전송하는 데이터가 Pydantic 유효성 검사를 통과하지 못했을 것입니다. 브라우저 콘솔을 확인하십시오 — errorData.detail이 어떤 필드에 문제가 있는지 보여줄 것입니다.
  • 415 Unsupported Media Type 오류: 'Content-Type': 'application/json' 헤더를 추가하는 것을 잊었을 수 있습니다.
  • 삭제 버튼이 작동하지 않음: 이벤트 위임이 올바르게 작동하고 data-ship-id에서 shipId를 올바르게 가져오는지 확인하십시오.