A raw Node HTTP server works, but routing and body parsing by hand get tedious fast. Express is a thin layer over http that gives you routes, middleware and static file serving.
Learning objectives
- Create an Express app and start a server.
- Define routes for GET and POST.
- Understand middleware and the order it runs in.
- Serve static files and return JSON.
1. Setup
npm init -y
npm install express
const express = require("express");
const app = express();
const PORT = process.env.PORT || 3000;
app.get("/", (req, res) => {
res.send("Hello from Express");
});
app.listen(PORT, () => {
console.log(`http://localhost:${PORT}`);
});
app.listen keeps the process alive. Stop it with Ctrl+C.
2. Routes
app.get("/about", (req, res) => res.send("About us"));
app.get("/users/:id", (req, res) => {
res.json({ id: req.params.id });
});
app.get("/search", (req, res) => {
res.json({ q: req.query.q ?? "" }); // /search?q=node
});
app.post("/users", (req, res) => {
res.status(201).json({ created: true, body: req.body });
});
req.params— values from the path (:id).req.query— values after?.req.body— parsed request body, only afterexpress.json().
Response helpers: res.send (text/HTML), res.json, res.status(code).json(...), res.sendFile(absolutePath), res.redirect(url).
3. Middleware
Middleware is a function (req, res, next) that runs before the route handler. Call next() to continue; send a response to stop.
app.use(express.json()); // parse JSON bodies
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
Order matters: middleware registered before a route runs before it. express.json() must be registered before any handler that reads req.body.
4. Static files
const path = require("node:path");
app.use(express.static(path.join(__dirname, "public")));
Every file in public/ is now served at the matching URL: public/about.html → /about.html, public/logo.png → /logo.png.
5. 404 and error handling
A catch-all middleware at the end handles unmatched routes:
app.use((req, res) => {
res.status(404).sendFile(path.join(__dirname, "public", "404.html"));
});
Error middleware takes four arguments and must be registered last:
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: "Something went wrong" });
});
Common mistakes
- Registering the 404 handler before the routes — it then catches everything.
- Reading
req.bodywithoutexpress.json(). - Using a relative path with
sendFile; Express resolves it against the process cwd. Always usepath.join(__dirname, ...).
Practice
Build the small portfolio server in the assignment: static pages, two JSON endpoints, request logging and a real 404 page.