Middlewares en Express — la cadena req → res → next
Express está construido enteramente sobre un concepto: una cadena de funciones (middlewares) que reciben la request en orden, y cada una decide si la maneja, la modifica, o se la pasa a la siguiente. Esto es justo lo que el servidor HTTP nativo de Node no tiene — ahí next() no existe, es un concepto que Express agrega.
La firma
Sección titulada «La firma»import express from "express"
const app = express()
app.use((req, res, next) => { console.log(`${req.method} ${req.url}`) next() // sin esto, la request se queda colgada aquí para siempre})
app.get("/usuarios", (req, res) => { res.json({ usuarios: [] })})Cada middleware recibe tres argumentos: req (la request, extendida con helpers que Node nativo no tiene — req.body, req.params, req.query, ya parseados), res (la response, con res.json(), res.status(), etc.), y next — una función que hay que llamar para pasarle el control al siguiente middleware de la cadena. Un handler de ruta (app.get(...)) es, en el fondo, el último eslabón de esa misma cadena.
Orden de ejecución
Sección titulada «Orden de ejecución»Los middlewares se ejecutan en el orden en que se registran con app.use(), no en el orden en que aparecen en el archivo si están en archivos distintos importados en otro orden — el orden real es el de las llamadas a .use()/.get()/etc., de arriba hacia abajo.
app.use(middlewareA) // corre primeroapp.use(middlewareB) // corre segundo, solo si A llamó a next()app.get("/ruta", handler) // corre últimoMiddleware global y middleware de ruta
Sección titulada «Middleware global y middleware de ruta»app.use(loggerGlobal) // corre en TODAS las rutasapp.get("/admin", verificarAdmin, handler) // corre SOLO para esta ruta, antes del handlerapp.get("/publico", handler) // no pasa por verificarAdminPasar varios middlewares antes del handler final (como verificarAdmin arriba) es exactamente la misma cadena — cada uno decide si llama a next() (sigue) o corta la cadena (por ejemplo, respondiendo 403 sin avanzar).
Cortar la cadena sin llamar a next()
Sección titulada «Cortar la cadena sin llamar a next()»function verificarAdmin(req, res, next) { if (!req.user?.esAdmin) { return res.status(403).json({ error: "No autorizado" }) // corta aquí, nunca llega al handler } next() // es admin, seguir}Si un middleware envía una respuesta (res.json(), res.send(), etc.) y también llama a next(), Express sigue ejecutando la cadena sobre una respuesta ya enviada — normalmente un error (Cannot set headers after they are sent). La regla es: o respondes o llamas a next(), nunca ambas acciones.
Middleware propio vs de terceros
Sección titulada «Middleware propio vs de terceros»import cors from "cors"import express from "express"// de terceros: paquete npmimport { logger } from "./middlewares/logger"
// propio: código del proyecto
const app = express()
app.use(express.json()) // viene incluido con Express: parsea el body JSONapp.use(cors()) // de tercerosapp.use(logger) // propioexpress.json() es el reemplazo directo del parseo manual de body que se hacía a mano en Node puro — ya viene con Express, no hace falta instalarlo aparte.
Cadena de consulta
Sección titulada «Cadena de consulta»| Concepto | Qué es |
|---|---|
(req, res, next) => {...} | La firma de cualquier middleware |
next() | Pasa el control al siguiente eslabón de la cadena |
app.use(fn) | Middleware global, corre en toda request |
app.get(ruta, mw1, mw2, handler) | Middlewares específicos de una ruta, en orden |
express.json() | Parseo de body JSON, incluido con Express |
Reglas de orden y terminación
Sección titulada «Reglas de orden y terminación»- Olvidar
next()en un middleware que no responde nada deja la request colgada indefinidamente hasta el timeout del cliente — el bug más común al escribir un middleware nuevo. - El orden de
app.use()importa de verdad: un middleware de auth registrado después de las rutas que debería proteger, no las protege — corre después de que el handler ya respondió. - Middlewares con 4 argumentos (
err, req, res, next) son un caso especial: manejo de errores. Ver Manejo de errores centralizado.