Middleware es una función del pipeline de solicitudes que inspecciona o modifica solicitudes y respuestas antes de que corra la lógica de tu ruta. Dos sentidos comparten la palabra — el sentido empresarial más antiguo (message brokers y buses de integración entre aplicaciones) y el sentido de framework web que cubre esta entrada: funciones dentro de una aplicación por las que fluye cada solicitud, en orden. Express enuncia el modelo sin rodeos: una app “es esencialmente una serie de llamadas a funciones de middleware” — y el orden de esas llamadas es, muy literalmente, el programa.
Puntos clave
| Pregunta | Respuesta |
|---|---|
| El contrato | Inspeccionar/modificar → luego responder (short-circuit) o llamar a next() |
| La forma | Una cebolla: las solicitudes bajan por el stack, las respuestas suben de regreso |
| La ley | Orden de registro = orden de ejecución — la mayoría de los bugs de middleware son bugs de orden |
| El stack canónico | Headers → CORS → parsing → logging → authn → authz → límites → rutas → 404 → errores |
| vs. el gateway | El middleware corre dentro de una app; un gateway va delante de muchos |
El stack, en orden
// JavaScript / Node.js — Express + Parse Server
// Middleware: functions the request flows through, in registration order
const app = express();
app.use(helmet()); // 1 · security headers
app.use(cors(corsOptions)); // 2 · CORS before anything that fails
app.use(express.json({ limit: '1mb' })); // 3 · body parsing, bounded
// Parse Server IS middleware — a whole backend mounted into the stack
app.use('/parse', new ParseServer(config).app);
app.use(notFoundHandler); // 404 — after all routes
app.use(errorHandler); // error handler LAST (4 args) // Flutter / Dart — Back4app Flutter SDK
// One SDK call — and the platform's middleware stack ran the gauntlet:
final response =
await QueryBuilder<ParseObject>(ParseObject('Post')).query();
// Before your query touched data, the request passed through:
// security headers → CORS → body limits → key check → session auth
// → rate limiting → routing → (your beforeFind trigger) → the database
// You wrote none of it — that's the middleware a BaaS runs for you. // iOS / Swift — Back4app Swift SDK
// One SDK call — and the platform's middleware stack ran the gauntlet:
let posts = try await Post.query().find()
// Before your query touched data, the request passed through:
// security headers → CORS → body limits → key check → session auth
// → rate limiting → routing → (your beforeFind trigger) → the database
// You wrote none of it — that's the middleware a BaaS runs for you. // Android / Kotlin — Back4app Android SDK
// One SDK call — and the platform's middleware stack ran the gauntlet:
val posts = ParseQuery.getQuery<ParseObject>("Post").find()
// Before your query touched data, the request passed through:
// security headers → CORS → body limits → key check → session auth
// → rate limiting → routing → (your beforeFind trigger) → the database
// You wrote none of it — that's the middleware a BaaS runs for you. Cada posición tiene su porqué: headers de seguridad primero (deben estar en toda respuesta, incluidos los errores); CORS antes que cualquier cosa que pueda fallar (o los navegadores enmascaran el error real); parsing del body acotado y antes de las rutas (o req.body queda undefined); autenticación antes que autorización (permisos verificados contra nadie son permisos concedidos a cualquiera); rate limiting antes del trabajo caro (un limitador después de la consulta a la base no protege nada); el 404 después de todas las rutas; el handler de errores al último, sin excepción.
La cebolla, bien dibujada
La mitad que la mayoría de las explicaciones omite: el pipeline corre en ambos sentidos. La documentación de Django lo dibuja como una cebolla — cada middleware es una capa alrededor de la vista en el núcleo — y el código después de la llamada a next() (o después de get_response) corre en el camino de regreso de la respuesta, en orden inverso. Ahí es donde se mide el tiempo de respuesta, donde se estampan los headers y donde el logging registra lo que de verdad pasó. Una capa que hace short-circuit no se salta solo el handler; se salta las dos mitades de cada capa interna — que es exactamente la garantía que una puerta de auth existe para dar.
Bugs de orden que llegan a producción
El consejo genérico es “el orden importa”; los bugs específicos enseñan más. Autorización antes de autenticación: la verificación de permisos corre contra un principal anónimo — 401s/403s intermitentes, ninguna excepción en ningún lado, horas de depuración. Body parser después de las rutas: todo handler ve req.body === undefined y culpa al cliente. Auth antes de CORS: el navegador bloquea la propia respuesta 401 por carecer de headers CORS, así que el frontend ve un error de red en lugar del error real. Archivos estáticos antes de auth: archivos privados servidos alegremente a los no autenticados. Handler de errores que no es el último: los errores lanzados después de su posición en el stack nunca le llegan. Cada uno de estos pasa un smoke test en el camino feliz — los bugs de orden son de los que llegan a producción.
Short-circuit: cuando no llamar a next() es el objetivo
El contrato tiene dos salidas legales: pasar el control adelante, o terminar el ciclo. Terminarlo temprano no es una falla del middleware — es la mitad de su trabajo: el 401 de la puerta de auth, el 429 del limitador, el cache hit, el redirect, el preflight de CORS respondido en el acto. La regla que mantiene honestas ambas salidas: haz siempre exactamente una — responde, o llama a next(). No hacer ninguna cuelga la solicitud para siempre; hacer ambas lanza errores de headers-already-sent que confunden a todos río abajo.
La misma idea en todos los frameworks
| Framework | El middleware es | Pasa el control | En el camino de regreso |
|---|---|---|---|
| Express | (req, res, next) => {} | next() | Código después de next() (con cuidado) |
| Django | Callable que envuelve get_response | get_response(request) | Código después de la llamada — la cebolla |
| Rack / Rails | Objeto con call(env) | @app.call(env) | Después de que la llamada retorna |
| Koa / Hono | async (ctx, next) => {} | await next() | Después del await — de primera clase |
Un modelo, cuatro acentos. El camino de error recibe su propia convención por framework — la firma de cuatro argumentos (err, req, res, next) de Express es el mecanismo de registro, y por eso borrar un parámetro “sin usar” convierte en silencio el handler de errores en un middleware común que nunca se dispara.
Middleware vs. gateways vs. hooks
| Middleware | API gateway | Hooks de datos | |
|---|---|---|---|
| Corre | Dentro del proceso de una app | Delante de muchas apps | Alrededor de las operaciones de datos |
| Granularidad | Por solicitud | Por solicitud, entre servicios | Por save/delete/find |
| Es dueño de | El pipeline de este app | Enrutamiento, auth de borde, límites globales | Validación, reacciones a los datos |
| Se configura con | Código, en orden | Config de infraestructura | Registro por clase |
Tres capas de intercepción, un anidamiento: el gateway va delante de la flota, el middleware corre la batería de cada app, y los hooks se disparan donde las solicitudes se convierten en datos. Una preocupación pertenece a la capa más externa capaz de decidirla — rate limits globales en el gateway, auth de sesión en el middleware, “¿es válida esta escritura?” en el hook.
Casos de uso comunes
- Autenticación y manejo de sesiones — establecer identidad una vez, temprano, para todo lo que sigue.
- Higiene transversal — CORS, headers de seguridad, compresión, IDs de solicitud.
- Disciplina de entrada — parsing del body con límites de tamaño, enforcement de content-type, validación.
- Observabilidad — logging y medición de tiempos envolviendo el pipeline entero por el camino de regreso de la cebolla.
- Protección de tráfico — rate limits y puertas antiabuso que hacen short-circuit antes de incurrir en el costo.
¿En qué capa va esto? Matriz de decisión
| Preocupación | Capa |
|---|---|
| Aplica a todas las apps que corres | Gateway |
| Aplica a toda solicitud de este app | Middleware, posicionado deliberadamente |
| Aplica a rutas específicas | Middleware a nivel de ruta |
| Aplica cuando los datos se escriben o se leen | Hooks beforeSave / beforeFind |
| Operaciones de negocio a la medida | Funciones, no parches de pipeline |
| Dar forma a los errores | Middleware de errores — al último, cuatro argumentos, sin excepciones |
Limitaciones y trade-offs
- El orden es invisible hasta que deja de serlo. El stack se lee de arriba abajo, pero falla apuntando a cualquier otra parte; trata el registro de middleware como código revisado y estructural.
- Cada capa le cobra a cada solicitud. Diez middleware de 2 ms cada uno son 20 ms en cada respuesta; mide el stack como mides las consultas.
- El estado global es una trampa. El middleware corre de forma concurrente entre solicitudes; cualquier cosa mutable compartida se vuelve una carrera — adjunta los datos por solicitud al objeto de la solicitud, y a ningún otro lugar.
- Los pipelines esconden el flujo de control. Una capa con short-circuit tres niveles abajo puede ser la razón de que una ruta “nunca corra”; la jugada de depuración es siempre la misma: imprime el stack, en orden.
- No todo es asunto del pipeline. La lógica de negocio contrabandeada al middleware acopla cada ruta a ella; el pipeline es para preocupaciones transversales, no centrales.
Middleware en Back4app
Back4app es una plataforma open-source de Backend as a Service (BaaS) que combina base de datos gestionada, APIs REST y GraphQL generadas automáticamente, autenticación, almacenamiento de archivos y funciones serverless con Cloud Code. La relación aquí es inusualmente literal: el servidor de Back4app es, él mismo, middleware de Express — la pestaña de JavaScript lo muestra montado con app.use('/parse', …) en un stack estándar — y la plataforma corre la batería canónica para cada solicitud: headers de seguridad, CORS, parsing acotado, verificación de claves, autenticación de sesión y rate limits, en el orden correcto, mantenidos como infraestructura. Tu lógica por solicitud va entonces adonde apunta la matriz de decisión, en lugar de a código de pipeline hecho a mano: triggers beforeSave/beforeFind para reglas junto a los datos, Cloud Functions para operaciones — cada uno con el contexto de usuario de la solicitud adjunto, que es la mayor parte de lo que un middleware a la medida siempre quiso saber.
Preguntas frecuentes
¿Qué es middleware en términos simples?
Una función que se interpone entre una solicitud entrante y la lógica de tu ruta, procesando cada solicitud a su paso — como los controles de seguridad del aeropuerto antes de la puerta de embarque. Cada una inspecciona o modifica la solicitud, y luego la deja pasar o la frena en seco.
¿Cuáles son ejemplos comunes de middleware?
El stack de siempre: headers de seguridad, CORS, parsing del body con límites de tamaño, logging, autenticación, autorización, rate limiting, archivos estáticos y — al final — los handlers de 404 y de errores. Casi todo lo transversal en una aplicación web es middleware.
¿Cómo funciona la cadena de middleware?
Cada función o bien termina el ciclo enviando una respuesta, o bien llama a next() para pasar el control a la siguiente; el framework recorre el stack en orden de registro hasta que algo responde. El bug clásico: no responder ni llamar a next() — la solicitud queda colgada para siempre.
¿Importa el orden del middleware?
Es la fuente número uno de bugs. Autorización antes de autenticación verifica permisos contra nadie; un body parser después de las rutas deja req.body undefined; auth antes de CORS hace que el navegador enmascare el error real; un handler de errores en cualquier lugar que no sea el último no atrapa nada. El orden es el programa.
¿Qué es el middleware de manejo de errores?
Un middleware al que el framework enruta los errores en lugar de a la cadena normal — en Express, reconocido por su firma de cuatro argumentos (err, req, res, next) y registrado al final. Los errores lanzados y las llamadas next(err) se saltan todo lo demás y aterrizan ahí, y por eso su posición es innegociable.
¿Cuál es la diferencia entre middleware y un handler de ruta?
Intención y posición. El middleware atiende preocupaciones transversales de muchas rutas y normalmente pasa el control adelante; el handler de ruta es el destino que produce la respuesta. En la mayoría de los frameworks son funciones estructuralmente idénticas — el pipeline simplemente termina en una de ellas.
¿Cuál es la diferencia entre middleware y un API gateway?
El alcance. El middleware corre dentro del proceso de una aplicación, por solicitud; un gateway es infraestructura delante de muchas aplicaciones, encargándose de enrutamiento, auth y rate limits entre servicios. Un gateway es el middleware de tu arquitectura entera — y se componen en lugar de competir.
¿Cuándo NO debería el middleware llamar a next()?
Cuando ya atendió la solicitud por completo: un rechazo de auth devolviendo 401, un rate limiter devolviendo 429, un cache hit, un redirect, una respuesta de preflight de CORS. El short-circuit es la función — la garantía de que nada después de la puerta corre para las solicitudes que fallaron en ella.