Express.js Fundamentals & Routing
📖 Concept
Express.js is a minimal, unopinionated web framework for Node.js. It sits on top of the built-in http module and provides a clean API for routing, middleware, and request/response enhancement.
Why Express?
- 30K+ GitHub stars, most downloaded Node.js framework (~30M weekly npm downloads)
- Minimal core — extend with middleware for exactly what you need
- Huge ecosystem of middleware packages
- Used by Uber, IBM, PayPal, Twitter
Core concepts:
- Application —
const app = express()— your Express application - Routes — Map URL patterns + HTTP methods to handler functions
- Middleware — Functions that process requests before they reach route handlers
- Request (req) — Enhanced IncomingMessage with parsed body, params, query
- Response (res) — Enhanced ServerResponse with
.json(),.send(),.status()
Routing patterns:
app.get('/users', handler) // GET /users
app.post('/users', handler) // POST /users
app.put('/users/:id', handler) // PUT /users/123
app.delete('/users/:id', handler) // DELETE /users/123
app.all('/api/*', handler) // Any method, any path under /api/
app.use('/admin', adminRouter) // Mount sub-router
Route parameters:
// :id captures the value as req.params.id
app.get('/users/:id/posts/:postId', (req, res) => {
const { id, postId } = req.params; // { id: '42', postId: '7' }
});
Express added features over raw http:
| Feature | Raw http | Express |
|---|---|---|
| Routing | Manual if/else | app.get(), app.post(), Router |
| Body parsing | Manual stream collection | express.json() middleware |
| Query params | Manual URL parsing | req.query (auto-parsed) |
| Static files | Manual MIME + streaming | express.static() |
| JSON response | Manual JSON.stringify + headers |
res.json() |
🏠 Real-world analogy: If the raw http module is building a house from scratch (foundation, framing, plumbing), Express is like a pre-fabricated house kit — the structure is ready, you just customize the rooms (routes) and add furniture (middleware).
💻 Code Example
1// Express.js — Complete API Server23const express = require("express");4const app = express();56// Built-in middleware7app.use(express.json({ limit: "10mb" }));8app.use(express.urlencoded({ extended: true }));9app.use(express.static("public"));1011// In-memory data store (use a database in production!)12let users = [13 { id: 1, name: "Alice", email: "alice@example.com", role: "admin" },14 { id: 2, name: "Bob", email: "bob@example.com", role: "user" },15 { id: 3, name: "Charlie", email: "charlie@example.com", role: "user" },16];17let nextId = 4;1819// === ROUTES ===2021// GET /api/users — List all users (with query filters)22app.get("/api/users", (req, res) => {23 let result = [...users];2425 // Filter by role26 if (req.query.role) {27 result = result.filter((u) => u.role === req.query.role);28 }2930 // Search by name31 if (req.query.search) {32 const search = req.query.search.toLowerCase();33 result = result.filter((u) => u.name.toLowerCase().includes(search));34 }3536 // Pagination37 const page = parseInt(req.query.page) || 1;38 const limit = parseInt(req.query.limit) || 10;39 const start = (page - 1) * limit;40 const paginated = result.slice(start, start + limit);4142 res.json({43 data: paginated,44 meta: {45 total: result.length,46 page,47 limit,48 totalPages: Math.ceil(result.length / limit),49 },50 });51});5253// GET /api/users/:id — Get a specific user54app.get("/api/users/:id", (req, res) => {55 const id = parseInt(req.params.id);56 const user = users.find((u) => u.id === id);5758 if (!user) {59 return res.status(404).json({ error: "User not found" });60 }6162 res.json({ data: user });63});6465// POST /api/users — Create a new user66app.post("/api/users", (req, res) => {67 const { name, email, role } = req.body;6869 // Validation70 if (!name || !email) {71 return res.status(400).json({72 error: "Validation failed",73 details: {74 ...(!name && { name: "Name is required" }),75 ...(!email && { email: "Email is required" }),76 },77 });78 }7980 // Check duplicate email81 if (users.some((u) => u.email === email)) {82 return res.status(409).json({ error: "Email already exists" });83 }8485 const newUser = { id: nextId++, name, email, role: role || "user" };86 users.push(newUser);8788 res.status(201).json({ data: newUser });89});9091// PUT /api/users/:id — Update a user92app.put("/api/users/:id", (req, res) => {93 const id = parseInt(req.params.id);94 const index = users.findIndex((u) => u.id === id);9596 if (index === -1) {97 return res.status(404).json({ error: "User not found" });98 }99100 users[index] = { ...users[index], ...req.body, id }; // Don't allow ID change101 res.json({ data: users[index] });102});103104// DELETE /api/users/:id — Delete a user105app.delete("/api/users/:id", (req, res) => {106 const id = parseInt(req.params.id);107 const index = users.findIndex((u) => u.id === id);108109 if (index === -1) {110 return res.status(404).json({ error: "User not found" });111 }112113 users.splice(index, 1);114 res.status(204).end();115});116117// Health check118app.get("/health", (req, res) => {119 res.json({ status: "healthy", uptime: process.uptime() });120});121122// 404 handler (must come after all routes)123app.use((req, res) => {124 res.status(404).json({ error: `Route ${req.method} ${req.path} not found` });125});126127// Start server128const PORT = process.env.PORT || 3000;129app.listen(PORT, () => {130 console.log(`Express server running on http://localhost:${PORT}`);131});
🏋️ Practice Exercise
Exercises:
- Build a complete CRUD REST API for a "todos" resource with Express
- Add query parameter support: filtering, searching, sorting, and pagination
- Implement route parameter validation (check that
:idis a valid integer) - Create a Router module that separates user routes into their own file
- Add a catch-all 404 handler and test it with invalid routes
- Build a simple HTML form that submits data to your Express API using
express.urlencoded()
⚠️ Common Mistakes
Not calling
next()in middleware — the request hangs forever because Express doesn't know to proceed to the next handlerDefining error-handling middleware before routes — Express middleware runs in order; put error handlers AFTER all routes
Sending multiple responses — calling
res.json()orres.send()more than once throws an error; usereturnafter sendingUsing
app.listen()in the same file asappcreation — this makes testing impossible; exportappseparately from the listen callNot using
express.json()middleware — without it,req.bodyisundefinedfor JSON POST/PUT requests
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for Express.js Fundamentals & Routing. Login to unlock this feature.