← Node & Express

Middleware

¿Por qué importa el orden en que registras los middleware y las rutas en Express?

Ver respuesta — intenta responderla en voz alta primero

Importa porque Express ejecuta los middleware y las rutas de arriba hacia abajo, en el mismo orden en que los registraste. Cada petición recorre esa cadena en secuencia. Si colocas un middleware después de la ruta que responde, ese middleware no se ejecutará para esa ruta, porque la respuesta ya terminó antes de llegar a él. Además, si un middleware olvida llamar a next(), corta la cadena y cuelga la petición.

Express no es "mágico": no busca el middleware más apropiado ni los ejecuta en un orden inteligente. Simplemente arma una lista con todo lo que registraste (app.use, app.get, app.post, etc.), en el orden exacto en que escribiste el código, y por cada petición recorre esa lista de arriba a abajo.

De ahí salen dos reglas prácticas:

  • Lo transversal va primero. Cosas como el parseo del body (express.json()), los logs o la autenticación deben registrarse antes de las rutas que dependen de ellas. Si pones express.json() después de tus rutas, cuando la ruta corra el req.body todavía no existirá.
  • La cadena se recorre hasta que alguien responde. En cuanto un middleware o ruta termina la respuesta (res.send, res.json...) y no llama a next(), la petición se detiene ahí. Todo lo que esté registrado más abajo no corre para esa petición.

Un caso muy típico de confusión: registras una ruta que responde, y debajo pones un middleware pensando que "va a correr para todo". No va a correr para esa ruta, porque la ruta ya cerró la respuesta antes de que Express llegara a tu middleware.

Otra fuente de bugs: un middleware que no llama a next() ni responde. La cadena se queda atascada en él, y la petición nunca avanza ni contesta. El cliente se queda esperando.

Regla mental sencilla: de arriba abajo, hasta que alguien responda. Piensa en el orden de tu archivo como el orden real de ejecución.

const express = require("express");
const app = express();

// 1) Middleware global: corre PRIMERO en toda petición.
//    Va arriba a propósito, para que aplique a todas las rutas.
app.use((req, res, next) => {
  console.log(`[log] ${req.method} ${req.url}`);
  next(); // sin este next(), la petición se colgaría aquí
});

// 2) La ruta responde y NO llama a next().
//    En cuanto contesta, la cadena se detiene para esta petición.
app.get("/usuarios", (req, res) => {
  res.json({ usuarios: ["Ana", "Luis"] });
});

// 3) Este middleware está DESPUÉS de la ruta /usuarios.
//    NO se ejecuta cuando pides GET /usuarios, porque la ruta
//    de arriba ya terminó la respuesta antes de llegar aquí.
app.use((req, res, next) => {
  console.log("Este mensaje NUNCA aparece para GET /usuarios");
  next();
});

// 4) Middleware "catch-all" al final: solo lo alcanzan las peticiones
//    que NO fueron respondidas por ninguna ruta anterior (ej. rutas inexistentes).
app.use((req, res) => {
  res.status(404).json({ error: "Ruta no encontrada" });
});

app.listen(3000, () => {
  console.log("Servidor en http://localhost:3000");
});

Colocar express.json() (o cualquier middleware que prepara datos) después de las rutas que lo necesitan, y luego sorprenderse de que req.body llega como undefined. Como Express ejecuta de arriba abajo, cuando la ruta corre, el middleware de parseo todavía no se ejecutó. La solución es siempre registrar los middleware de preparación antes de las rutas. El otro clásico es poner un middleware "para todo" al final del archivo y esperar que aplique a rutas que ya respondieron: nunca se ejecuta para ellas.

"El orden importa porque Express ejecuta los middleware y las rutas de arriba hacia abajo, en el orden en que los registré, y recorre esa cadena hasta que alguien termina la respuesta. Por eso los middleware transversales, como express.json(), los logs o la autenticación, van arriba de las rutas que dependen de ellos: si los pongo después, cuando la ruta corre esos datos todavía no están listos. También tengo cuidado con no olvidar next(), porque si un middleware ni responde ni llama a next(), la petición se cuelga. Y un manejador 404 lo pongo al final, para que solo lo alcancen las peticiones que ninguna ruta anterior respondió."

Reto rápido

Dado este código, ¿qué responde GET /perfil y por qué?

app.get("/perfil", (req, res) => {
  res.json({ nombre: "Mike" });
});

app.use((req, res, next) => {
  req.autenticado = true; // supuestamente autentica
  next();
});
Ver respuesta

Responde { "nombre": "Mike" }, sin autenticar. El middleware de autenticación está registrado después de la ruta /perfil, así que nunca se ejecuta para esa ruta: la ruta ya respondió y cortó la cadena antes de que Express llegara al middleware. Para que la autenticación aplique, hay que moverla arriba de la ruta. Este es exactamente el tipo de bug de orden que puede dejar rutas sin protección.