Chapter 3.4: CRUD Operations for Spacecraft
Time to learn: 1 hour
1. CRUD: The Full Lifecycle of Space Mission Management
So far, we have only been reading data (Read
). But a real Mission Control Center must be able to do everything:
- Create: Launch a new satellite into orbit.
- Read: Request the status of an existing spacecraft.
- Update: Adjust an orbit or update software.
- Delete: De-orbit an old satellite.
These four operations—CRUD—form the basis of most APIs. In this chapter, we will implement the full cycle for managing our fleet.
2. Create: Launching a New Ship (POST)
To create a new spacecraft, we will use the POST
method. The data for the new ship will be sent in the request body in JSON format.
Step 1: Create a new Pydantic model for incoming data
Why a new model? Because when creating a ship, we don't know its id
—it must be assigned by the server. We also need to update our main Spaceship
model to include the id
for responses.
Update your models in main.py
:
# main.py
from pydantic import BaseModel, Field
# This is our main model, now including an ID.
# It will be used for RESPONSE data.
class Spaceship(BaseModel):
id: int
name: str = Field(..., min_length=3, max_length=50)
type: str
launch_year: int = Field(..., gt=1950)
status: str
# This model is for INCOMING data when creating a ship.
# It has no ID.
class SpaceshipCreate(BaseModel):
name: str = Field(..., min_length=3, max_length=50)
type: str
launch_year: int = Field(..., gt=1950)
status: str
Step 2: Implement the POST /spaceships
endpoint
# main.py
import random # Add this import at the top of the file
from fastapi import FastAPI, HTTPException, Response, status # Update this import
# ... other code ...
@app.post("/spaceships", response_model=Spaceship, status_code=status.HTTP_201_CREATED)
def create_spaceship(ship: SpaceshipCreate):
"""
Adds a new spacecraft to the registry.
"""
# Generate a new unique ID for the ship
new_id = max(db_spaceships.keys() or [0]) + 1
# Create a spaceship object conforming to the full Spaceship model
# by combining the generated ID with the incoming data.
new_ship_data = ship.dict()
new_ship_data["id"] = new_id
new_ship = Spaceship(**new_ship_data)
# Save to our "database"
db_spaceships[new_id] = new_ship.dict()
return new_ship
@app.post(...)
: We use the decorator forPOST
requests.status_code=201
: We specify that on successful creation, the status201 Created
should be returned.ship: SpaceshipCreate
: This is the magic! FastAPI will automatically take the request body (JSON), validate it against theSpaceshipCreate
model, and pass it into the function as aship
object.new_id = ...
: Simple logic to generate a new ID.**ship.dict()
: We "unpack" the data from the receivedship
model.response_model=Spaceship
: The response will conform to the full model, including theid
.
3. Update: Course Correction (PUT)
The PUT
method is used for a full update of an existing resource.
Implement the PUT /spaceships/{ship_id}
endpoint:
# main.py
# ... other code ...
@app.put("/spaceships/{ship_id}", response_model=Spaceship)
def update_spaceship(ship_id: int, ship_update: SpaceshipCreate):
"""
Completely updates the data for a spacecraft.
"""
if ship_id not in db_spaceships:
raise HTTPException(status_code=404, detail="Spacecraft not found")
updated_ship_data = ship_update.dict()
updated_ship_data["id"] = ship_id
updated_ship = Spaceship(**updated_ship_data)
db_spaceships[ship_id] = updated_ship.dict()
return updated_ship
ship_update: SpaceshipCreate
: We again use our model to validate the incoming data.HTTPException
: If a ship with the givenid
is not found, we "raise" a standard FastAPI exception, which will be converted into a nice JSON response with a404
code.
4. Delete: De-orbiting (DELETE)
The DELETE
method is used to remove a resource. Typically, such an endpoint does not return a response body.
Implement the DELETE /spaceships/{ship_id}
endpoint:
# main.py
# ... other code ...
@app.delete("/spaceships/{ship_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_spaceship(ship_id: int):
"""
Removes a spacecraft from the registry.
"""
if ship_id not in db_spaceships:
raise HTTPException(status_code=404, detail="Spacecraft not found")
del db_spaceships[ship_id]
# Return an empty response with a 204 status
return Response(status_code=status.HTTP_204_NO_CONTENT)
status_code=status.HTTP_204_NO_CONTENT
: We explicitly specify the204 No Content
status.del db_spaceships[ship_id]
: We delete the entry from our dictionary.return Response(...)
: We return an empty response, as the client does not need data about the deleted object.
5. Testing the Full Cycle in /docs
Your uvicorn
should have reloaded.
- Open
http://127.0.0.1:8000/docs
. You now have a full set of CRUD operations! - POST: Expand the
POST /spaceships
endpoint, click "Try it out," fill in the JSON body (e.g., create the "James Webb Telescope"), and click "Execute." You should get a201
response with the new telescope's data. - GET: Now execute
GET /spaceships
. Your new telescope should appear in the list. - PUT: Use the new telescope's ID to update its data via
PUT /spaceships/{ship_id}
. For example, change its status. - DELETE: Use the same ID to delete the telescope via
DELETE /spaceships/{ship_id}
. You should receive an empty response with a204
status. - Check: Execute
GET /spaceships
again to ensure the telescope has been removed from the list.
Review Quiz
🚀 Chapter Summary:
You have implemented the full CRUD cycle and transformed your API from a simple "information board" into a full-fledged Fleet Command Center!
- ✅ Create:
POST /spaceships
to launch new craft. - ✅ Read:
GET /spaceships
andGET /spaceships/{id}
to retrieve data. - ✅ Update:
PUT /spaceships/{id}
to update missions. - ✅ Delete:
DELETE /spaceships/{id}
to decommission craft.
Your fleet is under complete control! In the next chapter, we will see how FastAPI has automatically created a detailed "operating manual" for us—the interactive Swagger documentation.
📌 Checkpoint:
- All 5 endpoints (
GET
(2),POST
,PUT
,DELETE
) are visible and working in/docs
.- You can successfully create, read, update, and delete a resource.
- Requesting a non-existent ID returns a
404
error.⚠️ If you have errors:
NameError
: Check that you have importedHTTPException
,Response
, andstatus
.KeyError
: You are likely trying to access an ID that has already been deleted.- Incorrect
PUT
orPOST
behavior: Make sure you are using the correct Pydantic model in the function argument (SpaceshipCreate
).