El orden importa
Parte de la sección Conceptos básicos de Express del Journey de Node.js de Coddy. Lección 14 de 23.
Express ejecuta el middleware y las rutas en el orden en que tu código los añade, y una ruta que responde termina la solicitud ahí.
app.get('/bikes', (req, res) => {
res.json(bikes);
});
app.use((req, res, next) => {
res.set('Cache-Control', 'no-store');
next();
});res.set(name, value) añade un encabezado a la respuesta y debe ejecutarse antes de que se envíe la respuesta. Aquí, GET /bikes responde antes de que se alcance el middleware, así que su respuesta nunca recibe el encabezado: el middleware solo ve las solicitudes a las que ninguna ruta anterior ha respondido. El middleware que deba afectar a todas las respuestas va antes de las rutas y de express.static.
Desafío
FácilCada respuesta recibe un identificador, para que cuando un visitante informe de un problema puedas encontrar su solicitud en el registro. Todas las respuestas lo necesitan: las páginas, los datos de la API y los archivos de public.
- En
server.js, importarandomUUIDdenode:crypto. Cada llamada devuelve un nuevo identificador aleatorio, como3b241101-e2bb-4255-8caf-4136c566a962. - Añade un middleware que establezca un encabezado de respuesta llamado
X-Request-Id, con un nuevorandomUUID()para cada solicitud, y luego llame anext(). - Colócalo de modo que todas las solicitudes pasen por él, incluidos los archivos que envía
express.static. Una respuesta recibe el encabezado solo si el middleware se ejecuta antes de que algo responda.
Pruébalo: Pulsa «Ejecutar» y envía /api/recipes dos veces. En la pestaña Headers, X-Request-Id tiene un valor distinto cada vez. Envía /style.css y /: cada uno también lleva un X-Request-Id.
Pruébalo tú mismo
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') envía texto sin formato, por lo que cada título aparece en una línea aparte.
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');
});
Todas las lecciones de Conceptos básicos de Express
Practica por tu cuenta: Playground de Express