Topic 2 of 55
Express.js Fundamentals
Overview
Express.js is the minimal, unopinionated web framework for Node.js. It provides routing, middleware, and HTTP utilities — making it the standard starting point for building REST APIs in Node.js.
Syntax
javascript
import express from 'express';
const app = express();
// Middleware — runs before route handlers
app.use(express.json()); // parse JSON body
app.use(express.urlencoded({ extended: true })); // parse form data
app.use(cors()); // enable CORS
app.use(morgan('dev')); // request logging
// Routes
app.get('/users', (req, res) => { res.json(users); });
app.get('/users/:id', (req, res) => {
const user = users.find(u => u.id === req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
});
app.post('/users', async (req, res) => {
const user = await db.users.create(req.body);
res.status(201).json(user);
});
app.listen(3000, () => console.log('Server on :3000'));Common Pitfalls
- Middleware order matters — app.use() runs in the order defined. Error middleware (4 params) must come LAST.
- Always call next() or send a response — forgetting either hangs the request forever.
- Interview tip: Express is 'unopinionated' — it doesn't enforce structure. This is power AND responsibility. Use a layered architecture (routes → controllers → services → repositories).
Real-World Example
A complete Express router for a products API:
example
javascript
import { Router } from 'express';
import { z } from 'zod';
const router = Router();
const ProductSchema = z.object({
name: z.string().min(2).max(100),
price: z.number().positive(),
category: z.enum(['electronics', 'clothing', 'food']),
stock: z.number().int().min(0),
});
// GET /api/products
router.get('/', async (req, res, next) => {
try {
const { category, minPrice, maxPrice, limit = 20 } = req.query;
const products = await ProductService.findAll({ category, minPrice, maxPrice, limit });
res.json({ data: products, count: products.length });
} catch (error) {
next(error); // pass to error middleware
}
});
// POST /api/products
router.post('/', authenticate, authorize('admin'), async (req, res, next) => {
try {
const validated = ProductSchema.parse(req.body);
const product = await ProductService.create(validated);
res.status(201).json(product);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ errors: error.flatten() });
}
next(error);
}
});
export default router;