Menu
CoddyTech

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.

challenge icon

Desafío

Fácil

Cada 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.

  1. En server.js, importa randomUUID de node:crypto. Cada llamada devuelve un nuevo identificador aleatorio, como 3b241101-e2bb-4255-8caf-4136c566a962.
  2. Añade un middleware que establezca un encabezado de respuesta llamado X-Request-Id, con un nuevo randomUUID() para cada solicitud, y luego llame a next().
  3. 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