Express Cheatsheet
Route and Query Parameters
Use this Express reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Route Parameters — req.params
Named URL segments prefixed with :. Values are always strings.
// Route: /users/:id // URL: /users/42 app.get('/users/:id', (req, res) => { req.params.id; // '42' }); // Multiple params // Route: /orgs/:orgId/repos/:repoId app.get('/orgs/:orgId/repos/:repoId', (req, res) => { const { orgId, repoId } = req.params; // { orgId: 'acme', repoId: '7' } res.json({ orgId, repoId }); });
Optional Parameters
Append ? to make a segment optional (Express 4 via path-to-regexp).
// Matches /posts and /posts/123 app.get('/posts/:id?', (req, res) => { if (req.params.id) { res.json({ id: req.params.id }); // specific post } else { res.json({ all: true }); // all posts } });
Wildcard / Splat
Capture everything after a prefix.
// Express 4: unnamed * app.get('/files/*', (req, res) => { req.params[0]; // 'a/b/c.txt' for /files/a/b/c.txt }); // Express 5: named wildcard app.get('/files/*filepath', (req, res) => { req.params.filepath; // 'a/b/c.txt' });
Type Coercion (Manual)
Express never coerces params — always convert explicitly.
app.get('/items/:id', (req, res) => { const id = parseInt(req.params.id, 10); if (Number.isNaN(id)) return res.status(400).json({ error: 'Invalid id' }); // use id as number });
Regex Constraints (Express 4)
// :id must be digits only app.get('/users/:id(\\d+)', (req, res) => { // only matches /users/123, not /users/abc });
app.param() — Param Pre-processing
Runs once per route with a matching param name, before other handlers.
app.param('userId', async (req, res, next, value) => { try { const user = await db.users.findById(value); if (!user) return res.status(404).json({ error: 'User not found' }); req.loadedUser = user; next(); } catch (err) { next(err); } }); // Every route with :userId gets req.loadedUser automatically app.get('/users/:userId', (req, res) => res.json(req.loadedUser)); app.put('/users/:userId', (req, res) => { /* req.loadedUser ready */ }); app.get('/users/:userId/profile', (req, res) => res.json(req.loadedUser.profile));
Multiple params:
app.param(['postId', 'commentId'], async (req, res, next, value, name) => { // name = 'postId' or 'commentId', value = the actual string req[name] = await db[name + 's'].findById(value); if (!req[name]) return res.sendStatus(404); next(); });
Query Parameters — req.query
Parsed from the ?key=value portion of the URL. Always strings (or arrays/objects with extended).
// GET /search?q=node&sort=asc&page=2&limit=10 req.query.q; // 'node' req.query.sort; // 'asc' req.query.page; // '2' ← string req.query.limit; // '10' ← string req.query.missing; // undefined
Arrays
// GET /items?tags=js&tags=ts req.query.tags; // ['js', 'ts'] // GET /items?tags[]=js&tags[]=ts (extended parser only) req.query.tags; // ['js', 'ts']
Nested Objects (qs / extended parser)
// GET /items?filter[price][gte]=10&filter[price][lte]=100 req.query.filter; // { price: { gte: '10', lte: '100' } }
Query Parser Settings
// Default in Express 5: 'simple' (Node's querystring, no nesting) app.set('query parser', 'simple'); // Extended (qs library, supports nested objects) — the Express 4 default app.set('query parser', 'extended'); // Disable parsing entirely (req.query always {}) app.set('query parser', false); // Custom parser function app.set('query parser', (str) => new URLSearchParams(str));
Safe Querying Pattern
app.get('/users', (req, res) => { const page = Math.max(1, parseInt(req.query.page, 10) || 1); const limit = Math.min(100, parseInt(req.query.limit, 10) || 20); const sort = ['name', 'created_at'].includes(req.query.sort) ? req.query.sort : 'created_at'; const order = req.query.order === 'asc' ? 'asc' : 'desc'; // Never pass req.query directly to SQL — always validate/whitelist res.json(db.users.list({ page, limit, sort, order })); });
Combining Params and Query
// GET /teams/7/players?position=forward&active=true app.get('/teams/:teamId/players', (req, res) => { const teamId = req.params.teamId; // '7' const position = req.query.position; // 'forward' const active = req.query.active === 'true'; // boolean coercion res.json(db.players.list({ teamId, position, active })); });
Hash Fragments
Hash (#fragment) is never sent to the server — it lives in the browser only. You cannot read it from req.
Common Validation Patterns
// Validate UUID param const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; app.param('id', (req, res, next, val) => { if (!UUID_RE.test(val)) return res.status(400).json({ error: 'Invalid ID format' }); next(); }); // Validate query with express-validator const { query, validationResult } = require('express-validator'); app.get('/search', query('q').trim().isLength({ min: 1, max: 200 }), query('page').optional().isInt({ min: 1 }).toInt(), (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }); // ... } );