Express is the most widely used web framework in the Node.js ecosystem. It builds on the http module and adds readable routing, middleware, and handy helpers like res.json. Version 5 is the current version: it is the one npm install express installs.
A minimal server
// src/server.js (ES modules project: "type": "module" in package.json)
import express from "express";
const app = express();
app.use(express.json()); // parses JSON bodies -> req.body
app.get("/health", (req, res) => {
res.json({ status: "ok" }); // status 200 by default, JSON Content-Type
});
const port = Number(process.env.PORT ?? 3000);
app.listen(port, () => console.log(`API at http://localhost:${port}`));
Run it with node --watch src/server.js and test with curl http://localhost:3000/health.
Reading the request
const notes = [{ id: 1, titre: "Groceries", fait: false }];
// Path parameter: /notes/42 -> req.params.id === "42" (a STRING)
app.get("/notes/:id", (req, res) => {
const id = Number(req.params.id);
const note = notes.find((n) => n.id === id);
if (!note) return res.status(404).json({ error: "Note not found" });
res.json(note);
});
// Query string: /notes?fait=true -> req.query.fait === "true"
app.get("/notes", (req, res) => {
const { fait } = req.query;
const resultat = fait === undefined ? notes : notes.filter((n) => String(n.fait) === fait);
res.json(resultat);
});
// JSON body: requires app.use(express.json())
app.post("/notes", (req, res) => {
const note = { id: notes.length + 1, titre: req.body.titre, fait: false };
notes.push(note);
res.status(201).location(`/notes/${note.id}`).json(note);
});
Three sources of data, three objects: req.params, req.query, req.body. All of them come from the client: never trustworthy, always to be validated (lesson 3).
Essential status codes
| Code | Usage |
|---|---|
| 200 OK | Successful read or update |
| 201 Created | Resource created (with the Location header) |
| 204 No Content | Successful deletion, no body (res.status(204).end()) |
| 400 Bad Request | Invalid data |
| 401 / 403 | Not authenticated / not authorized |
| 404 Not Found | Resource does not exist |
| 500 | Server error |
Each request must receive a single response. The return in front of res.status(404)... avoids sending a second one (the Cannot set headers after they are sent error).
Grouping with express.Router
// src/routes/notes.js
import { Router } from "express";
export const notesRouter = Router();
notesRouter.get("/", listerNotes);
notesRouter.get("/:id", lireNote);
notesRouter.post("/", creerNote);
// src/server.js
app.use("/api/notes", notesRouter); // GET /api/notes/3 -> lireNote
What changes with Express 5
- Errors from
asynchandlers are automatically passed to the error handler (lesson 4). - Paths are stricter: a wildcard must be named (
/fichiers/*chemin), and an optional segment is written/livres{/:format}. - Without
express.json(),req.bodyisundefined(and no longer{}). req.queryis read-only;app.del()andres.sendfile()are gone.
Key takeaways
A route = method + path + handler. Read params, query, and body while converting them, respond only once with the right status, and organize resources with Router.
Exercises
Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.
Match a path against a route pattern
To understand routing, write
matchRoute(pattern, path):patternis a path like/notes/:id/commentaires/:cid. Return an object of the parameters ({ id: "3", cid: "7" }) ifpathmatches, otherwisenull. Segments without:must be identical; the number of segments must be the same; values are decoded withdecodeURIComponent. Ignore any query string (?...).function matchRoute(pattern, path) { // À compléter }GET /notes/:id route handler
Write the handler
getNote(req, res)used like this:app.get("/notes/:id", getNote). It looks in thenotesarray for the note whoseid(a number) matchesreq.params.id(a string):- found:
res.json(note); - non-integer id:
res.status(400).json({ error: "Identifiant invalide" }); - missing:
res.status(404).json({ error: "Note introuvable" }).
const notes = [ { id: 1, titre: "Courses" }, { id: 2, titre: "Réunion" }, ]; function getNote(req, res) { // À compléter }- found:
The right status code
A
POST /api/notesrequest successfully creates a note. Which status should you return?- 200 OK
- 201 Created
- 204 No Content
- 302 Found
End-of-lesson quiz
Where is
42inGET /notes/42?tri=datewith the route/notes/:id?- req.query.id
- req.params.id
- req.body.id
What is
req.bodyin Express 5 if no body parser is installed?- {}
- undefined
- An empty string
How do you write a path wildcard in Express 5?
- /fichiers/*
- /fichiers/*chemin
- /fichiers/(.*)
The rest of the course
- Middleware: Express's Processing Chain18 min
- Validating Incoming Data18 min
- Handling Errors with Express 515 min
- Structuring a Complete CRUD REST API20 min