Express
Express is the de-facto Node web framework. Routes, middleware, and a minimal request/response API — small enough to fit in your head, big enough to ship a real app.
Routes, middleware, error handling, validation
EXAMPLE
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import { z } from 'zod';
const app = express();
// 1) Global middleware — order matters
app.use(helmet()); // sensible security headers
app.use(cors({ origin: 'https://app.example.com', credentials: true }));
app.use(express.json({ limit: '100kb' }));
app.use((req, _res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
// 2) Routes
app.get('/health', (_req, res) => res.json({ ok: true }));
app.get('/users/:id', async (req, res, next) => {
try {
const user = await db.users.findOne({ id: req.params.id });
if (!user) return res.status(404).json({ error: 'not found' });
res.json(user);
} catch (e) { next(e); }
});
// 3) Validate input — Zod schema
const NewUser = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
});
app.post('/users', async (req, res, next) => {
try {
const data = NewUser.parse(req.body);
const user = await db.users.create(data);
res.status(201).json(user);
} catch (e) {
if (e instanceof z.ZodError) return res.status(400).json({ errors: e.issues });
next(e);
}
});
// 4) Routers — split routes across files
import { Router } from 'express';
const posts = Router();
posts.get('/', listPosts);
posts.get('/:id', getPost);
posts.post('/', createPost);
app.use('/posts', posts);
// 5) Auth middleware
function requireAuth(req, res, next) {
const token = req.headers.authorization?.replace('Bearer ', '');
const user = token && verifyJWT(token);
if (!user) return res.status(401).json({ error: 'unauthenticated' });
req.user = user;
next();
}
app.get('/me', requireAuth, (req, res) => res.json(req.user));
// 6) Global error handler — last middleware, 4 args
app.use((err, _req, res, _next) => {
console.error(err);
res.status(err.status ?? 500).json({ error: err.message ?? 'internal' });
});
// 7) Listen
const port = process.env.PORT ?? 3000;
const server = app.listen(port, () => console.log(`http://localhost:${port}`));
// 8) Graceful shutdown
for (const sig of ['SIGINT', 'SIGTERM']) {
process.on(sig, () => server.close(() => process.exit(0)));
}
Why it matters
Move every route into a Router and keep app.ts small — security headers, body parsing, error handler. The pattern scales from a side project to 200 routes without surprises.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
import express from 'express';
const app = express();
app.get('/', (req, res) => res.send('Hello!'));
app.listen(3000);
Try it Yourself »
Exercise
Define a GET route.
app.
('/', (req, res) => res.send('Hi'));
Three letters; the HTTP verb method.
Discussion
Loading…