Skip to content

Chapter 4.3: Sending POST/PUT/DELETE Requests

Study time: 1 hour


1. Active Commands: From Launch to Decommission

So far, our Mission Control has only requested information (GET). Now we will learn to send active commands:

  • POST: "Launch a new satellite into orbit!"
  • PUT: "Perform a full systems upgrade on the ISS!"
  • DELETE: "De-orbit the old Debris-123 craft!"

To do this, we will use fetch, but with additional parameters that describe our command.

💡 Space Analogy:

If GET is passive listening to the radio waves, then POST, PUT, and DELETE are active command transmissions. For this, we need to specify not only the "frequency" (URL) but also the command content (request body) and the communication protocol (headers).


2. Sending a POST Request: Launching a New Ship

To create a new resource, we send a POST request. The most important thing here is to pass the body of the request with the data of the new object.

Step 1: Add the creation form to index.html Let's place it after the "Request by ID" block.

<!-- index.html -->
<hr>
<h2>Launch a New Craft</h2>
<form id="create-ship-form">
    <input type="text" id="create-name" placeholder="Name" required><br>
    <input type="text" id="create-type" placeholder="Type" required><br>
    <input type="number" id="create-year" placeholder="Launch Year" required><br>
    <input type="text" id="create-status" placeholder="Status" required><br>
    <button type="submit">Launch</button>
</form>
<div id="create-status-message"></div>

Step 2: Add the logic to app.js

// app.js, at the end of the file

const createShipForm = document.getElementById('create-ship-form');
const createStatusMessage = document.getElementById('create-status-message');

async function createShip(event) {
    event.preventDefault();

    // 1. Collect data from the form into an object
    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 = 'Sending launch command...';

        // 2. Send the fetch request with parameters
        const response = await fetch(`${API_BASE_URL}/spaceships`, {
            method: 'POST', // Specify the method
            headers: {
                'Content-Type': 'application/json' // Tell the server we are sending JSON
            },
            body: JSON.stringify(shipData) // Convert the JavaScript object to a JSON string
        });

        if (!response.ok) {
            // If the server returned an error, try to read its body
            const errorData = await response.json();
            throw new Error(errorData.detail || `Server error: ${response.status}`);
        }

        const newShip = await response.json();
        createStatusMessage.textContent = `🚀 Successful launch! Craft assigned ID: ${newShip.id}`;

        createShipForm.reset(); // Clear the form
        fetchAndDisplayFleet(); // Refresh the fleet list

    } catch (error) {
        console.error('Error launching craft:', error);
        createStatusMessage.textContent = `🔴 Error: ${error.message}`;
    }
}

createShipForm.addEventListener('submit', createShip);
Key points of fetch for POST:

  • method: 'POST': It is mandatory to specify the HTTP method.
  • headers: { 'Content-Type': 'application/json' }: A critically important header. It tells our FastAPI server that the request body contains JSON and needs to be parsed.
  • body: JSON.stringify(shipData): We cannot send a JavaScript object directly. It needs to be serialized (converted) into a JSON string.

3. Sending a DELETE Request: Decommissioning a Craft

A delete request is simpler — it usually doesn't need a body, just the URL with the object's ID.

Step 1: Add a "Delete" button to our ship list Let's modify the fetchAndDisplayFleet function in app.js to add a delete button for each item.

// app.js, inside the fetchAndDisplayFleet function

// ...
ships.forEach(ship => {
    const listItem = document.createElement('li');
    // Add a button with a data-attribute storing the ID
    listItem.innerHTML = `
        <strong>${ship.name} (ID: ${ship.id})</strong><br>
        Type: ${ship.type} | Year: ${ship.launch_year} | Status: ${ship.status}<br>
        <button class="delete-btn" data-ship-id="${ship.id}">Decommission</button>
    `;
    fleetList.appendChild(listItem);
});
// ...

Step 2: Add a handler for all "Delete" buttons We use event delegation — one handler for the entire list.

// app.js, at the end of the file

async function deleteShip(shipId) {
    if (!confirm(`Are you sure you want to decommission the craft with ID ${shipId}? This action is irreversible.`)) {
        return;
    }

    try {
        const response = await fetch(`${API_BASE_URL}/spaceships/${shipId}`, {
            method: 'DELETE' // Specify the method
        });

        if (!response.ok) {
            throw new Error(`Failed to decommission craft. Status: ${response.status}`);
        }

        alert(`Craft with ID ${shipId} successfully decommissioned.`);
        fetchAndDisplayFleet(); // Refresh the list

    } catch (error) {
        console.error('Error during decommissioning:', error);
        alert(`Error: ${error.message}`);
    }
}

// Event delegation: listen for clicks on the entire list
fleetList.addEventListener('click', (event) => {
    // Check if the click was on a button with the class 'delete-btn'
    if (event.target.classList.contains('delete-btn')) {
        const shipId = event.target.dataset.shipId; // Get the ID from the data-attribute
        deleteShip(shipId);
    }
});

Step 3: Add id to the Spaceship model

Add the id to the models and the database in the main.py file

class Spaceship(BaseModel):
    id: int
    # Rest of the model code...

db_spaceships = {
    1: {
        "id": 1,
        # Data for item 1
    },
    2: {
        "id": 2,
        # Data for item 2
    },
    3: {
        "id": 3,
        # Data for item 3
    }
}
  • method: 'DELETE': Specify the method. Body and headers are not needed here.
  • confirm(): A simple built-in confirmation dialog to avoid accidentally deleting something important.

4. Sending a PUT Request (Independent Task)

Implementing a PUT request for an update is very similar to POST.

Your mission, should you choose to accept it:

  1. Add an "Edit" button next to the "Delete" button for each ship.
  2. When "Edit" is clicked, populate a form (you can use the same one as for creation) with the current data of the ship.
  3. Change the text of the "Launch" button to "Update".
  4. When the form is submitted, send a PUT request to /spaceships/{id} with the full body of the object.
  5. After a successful update — refresh the fleet list.

Hint: You will need fetch with method: 'PUT', Content-Type headers, and a body with JSON.stringify(), just like in the POST request.


Quiz to Reinforce

1. Which `fetch` parameter is used to pass data in the request body?

2. The `'Content-Type': 'application/json'` header tells the server that...

3. What does the `JSON.stringify(obj)` function in JavaScript do?

4. To send a `DELETE` request using `fetch`, you must specify:

5. Event delegation in JavaScript is when...


🚀 Chapter Summary:

Your Mission Control now has a full set of commands to manage the fleet!

  • ✅ You have learned to send POST requests with a body and headers to create new resources.
  • ✅ You have implemented DELETE requests to decommission obsolete craft.
  • ✅ You have received an assignment to implement a PUT request, reinforcing your knowledge.

Full control established! But what if the connection is lost or the server reports an error? In the next chapter, we will create a centralized error handling system on the frontend.

📌 Verification:

  • Make sure the form for creating a new ship works and that the list on the page is updated after successful creation.
  • Check that the "Decommission" button works, asks for confirmation, and removes the ship from the list.
  • Try to create a ship with invalid data (e.g., with a very short name) and look at the error that your FastAPI server returns.

⚠️ If there are errors:

  • 422 error from the server: Most likely, the data you are sending is not passing Pydantic validation. Check the browser console — errorData.detail will show which field has the problem.
  • 415 Unsupported Media Type error: You forgot to add the 'Content-Type': 'application/json' header.
  • Delete buttons don't work: Check that event delegation is working correctly and that you are correctly getting the shipId from data-ship-id.