Order Matters
Part of the Express Basics section of Coddy's Node.js journey. Lesson 14 of 23.
Express runs middleware and routes in the order your code adds them, and a route that answers ends the request there.
app.get('/bikes', (req, res) => {
res.json(bikes);
});
app.use((req, res, next) => {
res.set('Cache-Control', 'no-store');
next();
});res.set(name, value) adds a header to the response, and it must run before the response is sent. Here GET /bikes answers before the middleware is reached, so its response never gets the header: the middleware only sees requests no route above it answered. Middleware that should touch every response goes above the routes and above express.static.
Challenge
EasyEach response gets an id, so that when a visitor reports a problem you can find their request in your log. Every response needs one: pages, API data, and files from public.
- In
server.js, importrandomUUIDfromnode:crypto. Each call returns a new random id, like3b241101-e2bb-4255-8caf-4136c566a962. - Add a middleware that sets a response header named
X-Request-Id, holding a newrandomUUID()for each request, then callsnext(). - Place it so that every request passes through it, including the files
express.staticsends. A response gets the header only if the middleware runs before something responds.
Try it: Press Run and send /api/recipes twice. In the Headers tab, X-Request-Id has a different value each time. Send /style.css and /: each carries an X-Request-Id too.
Try it yourself
import { escapeHtml } from './html.js';
import express from 'express';
import { recipes } from './data.js';
const app = express();
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
app.use(express.static('public'));
app.get('/', (req, res) => {
const items = recipes.map((r) => `<li><a href="/recipes/${r.id}">${escapeHtml(r.title)}</a></li>`);
res.send(`<link rel="stylesheet" href="/style.css"><h1>Recipe Box</h1><ul>${items.join('')}</ul>`);
});
// type('text') sends plain text, so each title shows on its own line.
app.get('/recipes', (req, res) => {
const { tag } = req.query;
const list = tag ? recipes.filter((recipe) => recipe.tags.includes(tag)) : recipes;
res.type('text').send(list.map((recipe) => recipe.title).join('\n'));
});
app.get('/recipes/:id', (req, res) => {
const recipe = recipes.find((r) => r.id === Number(req.params.id));
if (!recipe) {
res.status(404).send('No such recipe');
return;
}
res.send(recipe.title);
});
app.get('/api/recipes', (req, res) => {
res.json(recipes);
});
app.get('/api/recipes/:id', (req, res) => {
const recipe = recipes.find((r) => r.id === Number(req.params.id));
if (!recipe) {
res.status(404).json({ error: 'No such recipe' });
return;
}
res.json(recipe);
});
app.get('/about', (req, res) => {
res.send('Recipe Box collects family recipes.');
});
app.get('/menu', (req, res) => {
res.redirect(301, '/recipes');
});
app.get('/menu/:id', (req, res) => {
res.redirect(301, `/recipes/${req.params.id}`);
});
app.listen(3000, () => {
console.log('Recipe Box is running on port 3000');
});
All lessons in Express Basics
3Middleware
Your First MiddlewarePractice on your own: Express playground