CRUD with an In-Memory Store
CRUD is the four things almost every API does: Create, Read, Update, Delete. This phase wires up all four over a place to keep the notes. We're using a plain Python dictionary on purpose - it keeps the focus on the routing and the HTTP, with no database to set up yet. Phase 5 swaps it for SQLite, and you'll see how little of this code changes.
One catch with an in-memory store: the data lives only while the server runs.
Restart it (or let --reload bounce it on a save) and you're back to empty.
That's fine for now - it's exactly why phase 5 exists.
Replace main.py
We've collected enough pieces to write the whole file cleanly. Replace the
contents of main.py with this:
=
:
:
: = False
# Our "database" for now: a dict of id -> note, plus a counter for new ids.
: =
= 1
return
return
global
=
=
+= 1
return
=
=
return
del
return
Walk through what each route does:
- list returns all the note records as a JSON array.
- get looks up one note by its id.
- create assigns the next id, stores the record, bumps the counter, and returns what it stored - including the new id, which the client needs.
- update overwrites the note at that id with the new data.
- delete removes the entry and confirms which id went.
The global next_id line is there because we reassign that module-level variable
inside the function. It's a little ugly - and it's another reason a real database
is nicer, since the database hands out ids for us. We'll get there.
Notice
getanddeletewill blow up if the id doesn't exist - aKeyErrorthat FastAPI turns into an ugly 500. We're leaving that on purpose. Phase 4 is all about turning those into clean 404s.
Test it with curl
Restart isn't needed - --reload already reloaded on save. Open a second
terminal (leave the server running in the first) and drive the API by hand.
Windows note: PowerShell aliases curl to its own command, so use curl.exe
there. On macOS/Linux plain curl is fine.
Create a note:
You'll get back the stored record with "id": 1. Create one more so we have
something to list:
List them:
You should see both notes in an array.
Read one:
Update it (PUT replaces the whole note):
List again and you'll see note 1 has changed.
Delete one:
List one final time - note 2 is gone.
The map of methods to operations
This pairing is a convention you'll see in nearly every REST API. Worth committing to memory:
| Operation | HTTP method | Path | What it does |
|---|---|---|---|
| Create | POST |
/notes |
add a new note |
| Read (all) | GET |
/notes |
list notes |
| Read (one) | GET |
/notes/{id} |
fetch a single note |
| Update | PUT |
/notes/{id} |
replace a note |
| Delete | DELETE |
/notes/{id} |
remove a note |
Two patterns fall out of this. POST and GET-all act on the collection
(/notes), while GET-one, PUT, and DELETE act on a specific member
(/notes/{id}). And the same path serves different operations depending on the
method - /notes is both "list" and "create", the method tells them apart.
Where we are
You have a full CRUD API. You can create notes, read them back, change them, and
remove them - all driven by the right HTTP methods, all testable with curl or the
/docs page. It's missing one thing a real API can't skip: it falls apart the
moment someone asks for a note that doesn't exist. That's the next phase.