Escritura de middleware para uso en aplicaciones Express
Las funciones de middleware son funciones que tienen acceso al objeto de solicitud (req), al objeto de respuesta (res), y a la función next en el ciclo solicitud-respuesta de la aplicación. La función next es una función del router de Express que, cuando se invoca, ejecuta el middleware que sigue al middleware actual.
Las funciones de middleware pueden realizar las siguientes tareas:
- Ejecutar cualquier código.
- Hacer cambios en los objetos de solicitud y respuesta.
- Finalizar el ciclo solicitud-respuesta.
- Llamar al siguiente middleware en la pila.
Si la función de middleware actual no finaliza el ciclo solicitud-respuesta, debe llamar a next() para pasar el control a la siguiente función de middleware. De lo contrario, la solicitud quedará colgada.
La siguiente figura muestra los elementos de una llamada a una función de middleware:

A partir de Express 5, las funciones de middleware que devuelven una Promise llamarán a next(value) cuando se rechacen o lancen un error. next será llamado con el valor rechazado o el Error lanzado.
Ejemplo
Aquí hay un ejemplo de una aplicación Express simple "Hello World".
El resto de este artículo definirá y añadirá tres funciones de middleware a la aplicación:
una llamada myLogger que imprime un mensaje de log simple, una llamada requestTime que
muestra el timestamp de la solicitud HTTP, y una llamada validateCookies que valida las cookies entrantes.
const express = require('express');const app = express();
app.get('/', (req, res) => { res.send('Hello World!');});
app.listen(3000);import express from 'express';
const app = express();
app.get('/', (req, res) => { res.send('Hello World!');});
app.listen(3000);Función de middleware myLogger
Aquí hay un ejemplo simple de una función de middleware llamada "myLogger". Esta función simplemente imprime
"LOGGED" cuando una solicitud a la aplicación pasa por ella. La función de middleware se asigna a una
variable llamada myLogger.
const myLogger = function (req, res, next) { console.log('LOGGED'); next();};Precaución
Nota la llamada anterior a next(). Llamar a esta función invoca la siguiente función de middleware en
la aplicación. La función next() no es parte de la API de Node.js o Express, pero es el tercer
argumento que se pasa a la función de middleware. La función next() podría llamarse de cualquier manera,
pero por convención siempre se llama "next". Para evitar confusiones, usa siempre esta convención.
Para cargar la función de middleware, llama a app.use(), especificando la función de middleware.
Por ejemplo, el siguiente código carga la función de middleware myLogger antes de la ruta a la ruta raíz (/).
const express = require('express');const app = express();
const myLogger = function (req, res, next) { console.log('LOGGED'); next();};
app.use(myLogger);
app.get('/', (req, res) => { res.send('Hello World!');});
app.listen(3000);import express from 'express';
const app = express();
const myLogger = function (req, res, next) { console.log('LOGGED'); next();};
app.use(myLogger);
app.get('/', (req, res) => { res.send('Hello World!');});
app.listen(3000);Cada vez que la aplicación recibe una solicitud, imprime el mensaje "LOGGED" en la terminal.
El orden de carga del middleware es importante: las funciones de middleware que se cargan primero también se ejecutan primero.
Si myLogger se carga después de la ruta a la ruta raíz, la solicitud nunca la alcanza y la aplicación no imprime "LOGGED", porque el manejador de ruta de la ruta raíz termina el ciclo solicitud-respuesta.
La función de middleware myLogger simplemente imprime un mensaje, luego pasa la solicitud a la siguiente función de middleware en la pila llamando a la función next().
Función de middleware requestTime
A continuación, crearemos una función de middleware llamada "requestTime" y añadiremos una propiedad llamada requestTime
al objeto de solicitud.
const requestTime = function (req, res, next) { req.requestTime = Date.now(); next();};La aplicación ahora usa la función de middleware requestTime. Además, la función de callback de la ruta raíz usa la propiedad que la función de middleware añade a req (el objeto de solicitud).
const express = require('express');const app = express();
const requestTime = function (req, res, next) { req.requestTime = Date.now(); next();};
app.use(requestTime);
app.get('/', (req, res) => { let responseText = 'Hello World!<br>'; responseText += `<small>Requested at: ${req.requestTime}</small>`; res.send(responseText);});
app.listen(3000);import express from 'express';
const app = express();
const requestTime = function (req, res, next) { req.requestTime = Date.now(); next();};
app.use(requestTime);
app.get('/', (req, res) => { let responseText = 'Hello World!<br>'; responseText += `<small>Requested at: ${req.requestTime}</small>`; res.send(responseText);});
app.listen(3000);Cuando haces una solicitud a la raíz de la aplicación, la aplicación ahora muestra el timestamp de tu solicitud en el navegador.
Función de middleware validateCookies
Finalmente, crearemos una función de middleware que valide las cookies entrantes y envíe una respuesta 400 si las cookies son inválidas.
Aquí hay una función de ejemplo que valida cookies con un servicio asincrónico externo.
async function cookieValidator(cookies) { try { await externallyValidateCookie(cookies.testCookie); } catch { throw new Error('Invalid cookies'); }}Aquí, usamos el middleware cookie-parser para analizar las cookies entrantes del objeto req y pasarlas a nuestra función cookieValidator. El middleware validateCookies devuelve una Promise que al rechazarse activará automáticamente nuestro manejador de errores.
const express = require('express');const cookieParser = require('cookie-parser');const cookieValidator = require('./cookieValidator');
const app = express();
async function validateCookies(req, res, next) { await cookieValidator(req.cookies); next();}
app.use(cookieParser());
app.use(validateCookies);
// error handlerapp.use((err, req, res, next) => { res.status(400).send(err.message);});
app.listen(3000);import express from 'express';import cookieParser from 'cookie-parser';import cookieValidator from './cookieValidator';
const app = express();
async function validateCookies(req, res, next) { await cookieValidator(req.cookies); next();}
app.use(cookieParser());
app.use(validateCookies);
// error handlerapp.use((err, req, res, next) => { res.status(400).send(err.message);});
app.listen(3000);Precaución
Nota cómo se llama a next() después de await cookieValidator(req.cookies). Esto asegura que si
cookieValidator se resuelve, el siguiente middleware en la pila será llamado. Si pasas cualquier cosa
a la función next() (excepto la cadena 'route' o 'router'), Express considera que la solicitud
actual es un error y omitirá cualquier función de enrutamiento y middleware restante que no sea de manejo de errores.
Como tienes acceso al objeto de solicitud, al objeto de respuesta, a la siguiente función de middleware en la pila, y a toda la API de Node.js, las posibilidades con las funciones de middleware son infinitas.
Para más información sobre el middleware de Express, consulta: Uso de middleware de Express.
Middleware configurable
Si necesitas que tu middleware sea configurable, exporta una función que acepte un objeto de opciones u otros parámetros, que luego devuelva la implementación del middleware basada en los parámetros de entrada.
module.exports = function (options) { return function (req, res, next) { // Implement the middleware function based on the options object next(); };};export default function (options) { return function (req, res, next) { // Implement the middleware function based on the options object next(); };}El middleware ahora puede usarse como se muestra a continuación.
const mw = require('./my-middleware.cjs');
app.use(mw({ option1: '1', option2: '2' }));import mw from './my-middleware.mjs';
app.use(mw({ option1: '1', option2: '2' }));Consulta cookie-session y compression para ejemplos de middleware configurable.