04 — REST API
Hub › JavaScript › Advanced › 04 REST API
Goal: replace the in-memory todo store with PostgreSQL-backed CRUD, turning the Express server into a real REST API.
Full server with Postgres
Create app.js — the Express app exported without listen() (for testing later):
js
const express = require("express");
const db = require("./db");
const app = express();
app.use(express.json());
app.get("/api/todos", async (_req, res, next) => {
try {
const todos = await db.getAllTodos();
res.json(todos);
} catch (err) {
next(err);
}
});
app.post("/api/todos", async (req, res, next) => {
try {
const { text } = req.body;
if (!text) return res.status(400).json({ error: "text is required" });
const todo = await db.createTodo(text);
res.status(201).json(todo);
} catch (err) {
next(err);
}
});
app.patch("/api/todos/:id", async (req, res, next) => {
try {
const todo = await db.updateTodo(Number(req.params.id), req.body);
if (!todo) return res.status(404).json({ error: "not found" });
res.json(todo);
} catch (err) {
next(err);
}
});
app.delete("/api/todos/:id", async (req, res, next) => {
try {
const deleted = await db.deleteTodo(Number(req.params.id));
if (!deleted) return res.status(404).json({ error: "not found" });
res.status(204).end();
} catch (err) {
next(err);
}
});
module.exports = app;Create server.js that imports app.js and starts listening:
js
const app = require("./app");
const { migrate } = require("./db");
const PORT = process.env.PORT || 3000;
migrate().then(() => {
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
});Checkpoint
bash
node server.js &
sleep 1
curl -s -X POST http://localhost:3000/api/todos -H 'Content-Type: application/json' -d '{"text":"restful todo"}'
# {"id":1,"text":"restful todo","done":false,"created_at":"2026-07-05T..."}
curl -s http://localhost:3000/api/todos
# [{"id":1,"text":"restful todo","done":false,"created_at":"2026-07-05T..."}]
curl -s -X PATCH http://localhost:3000/api/todos/1 -H 'Content-Type: application/json' -d '{"done":true}'
# {"id":1,"text":"restful todo","done":true,"created_at":"2026-07-05T..."}
curl -s -o /dev/null -w "%{http_code}" -X DELETE http://localhost:3000/api/todos/1
# 204
kill %1 2>/dev/nullThe API now persists across restarts. The data lives in PostgreSQL, not in memory.
Next: 05 JWT auth