Databases · 04/09 6 min1 hands-on
Connect a database to an API
Wire a model into Express routes: 201 on create, 400 for bad input, 404 when nothing's there.
This is the shape of nearly every backend you'll be asked to debug: a route receives a request, a controller talks to the model, and the response carries the right status code.
POST /todos → createTodo(req, res) → Todo.create(...) → 201 + todo
GET /todos/:id → getTodo(req, res) → Todo.findById(id) → 200 / 404 / 400
A controller, step by step
export async function getTodo(req, res) {
const { id } = req.params;
if (!mongoose.isValidObjectId(id)) // 1. reject garbage early
return res.status(400).json({ error: "bad id" });
const todo = await Todo.findById(id); // 2. ask the database (await!)
if (!todo) // 3. nothing there
return res.status(404).json({ error: "Todo not found" });
res.json(todo); // 4. happy path, 200
}
Notice the return before each early response. Without it the function keeps going and tries to answer twice.
Which status?
| Situation | Status |
|---|---|
| created something | 201 |
| found it | 200 |
| client sent bad data or a malformed id | 400 |
| valid id, no such record | 404 |
How the tests talk to your API
The tests use supertest: request(app).post("/todos").send({ title: "x" }) fires a real request at your Express app without starting a server, then check res.status and res.body.
Your turn · 1 exercise0/1 solved
Your first database-backed API
Finish the controller: POST /todos saves a todo (201, or 400 when title is missing), GET /todos/:id returns it (404 if missing, 400 for a malformed id).
Loading editor…
Next in Databases
Updating safely