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, thenPOST
,PUT
, andDELETE
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);
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:
- Add an "Edit" button next to the "Delete" button for each ship.
- When "Edit" is clicked, populate a form (you can use the same one as for creation) with the current data of the ship.
- Change the text of the "Launch" button to "Update".
- When the form is submitted, send a
PUT
request to/spaceships/{id}
with the full body of the object. - After a successful update — refresh the fleet list.
Hint: You will need
fetch
withmethod: 'PUT'
,Content-Type
headers, and abody
withJSON.stringify()
, just like in thePOST
request.
Quiz to Reinforce
🚀 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
fromdata-ship-id
.