Crear middleware personalizado
Los middlewares personalizados en Express nos permiten crear funciones específicas que se ejecuten durante el procesamiento de las peticiones HTTP. A diferencia de los middlewares integrados o de terceros, estos middlewares están diseñados para satisfacer las necesidades particulares de nuestra aplicación.
Un middleware personalizado es simplemente una función JavaScript que recibe tres parámetros: el objeto de petición (req
), el objeto de respuesta (res
) y una función next
que permite continuar con el siguiente middleware en la cadena. La estructura básica es siempre la misma, pero el contenido puede variar según nuestras necesidades.
Estructura básica de un middleware
La sintaxis fundamental para crear un middleware personalizado sigue este patrón:
function miMiddleware(req, res, next) {
// Lógica del middleware
console.log('Middleware ejecutado');
next(); // Continúa al siguiente middleware
}
Este middleware puede registrarse en nuestra aplicación Express de varias formas. La más común es utilizando el método use()
:
import express from 'express';
const app = express();
// Registrar el middleware personalizado
app.use(miMiddleware);
app.get('/', (req, res) => {
res.send('¡Hola desde Express!');
});
app.listen(3000);
Middlewares con funcionalidad específica
Los middlewares personalizados pueden realizar tareas muy diversas. Por ejemplo, podemos crear un middleware que registre información sobre cada petición:
function logger(req, res, next) {
const timestamp = new Date().toISOString();
const method = req.method;
const url = req.url;
console.log(`[${timestamp}] ${method} ${url}`);
next();
}
app.use(logger);
También podemos crear middlewares que modifiquen los objetos req
o res
para añadir funcionalidad adicional:
function addRequestId(req, res, next) {
// Generar un ID único para cada petición
req.id = Math.random().toString(36).substring(2, 15);
next();
}
app.use(addRequestId);
app.get('/usuario', (req, res) => {
res.json({
mensaje: 'Datos del usuario',
requestId: req.id // Usar el ID añadido por el middleware
});
});
Middlewares con parámetros
Una técnica muy útil es crear funciones que devuelvan middlewares, permitiendo parametrizar su comportamiento:
function validarApiKey(keyRequerida) {
return function(req, res, next) {
const apiKey = req.headers['x-api-key'];
if (apiKey !== keyRequerida) {
return res.status(401).json({ error: 'API key inválida' });
}
next();
};
}
// Usar el middleware parametrizado
app.use('/api', validarApiKey('mi-clave-secreta'));
Middlewares específicos para rutas
Los middlewares personalizados no tienen que aplicarse globalmente. Podemos crear middlewares que se ejecuten solo en rutas específicas:
function validarUsuario(req, res, next) {
const userId = req.params.id;
if (!userId || isNaN(userId)) {
return res.status(400).json({ error: 'ID de usuario inválido' });
}
// Convertir a número para facilitar su uso posterior
req.params.id = parseInt(userId);
next();
}
// Aplicar solo a esta ruta específica
app.get('/usuarios/:id', validarUsuario, (req, res) => {
res.json({
usuario: `Usuario con ID: ${req.params.id}`,
tipo: typeof req.params.id // Será 'number' gracias al middleware
});
});
Middlewares asíncronos
Con las funciones asíncronas modernas de JavaScript, podemos crear middlewares que realicen operaciones asíncronas:
async function verificarBaseDatos(req, res, next) {
try {
// Simular una consulta a base de datos
const resultado = await new Promise(resolve => {
setTimeout(() => resolve({ activa: true }), 100);
});
if (!resultado.activa) {
return res.status(503).json({ error: 'Base de datos no disponible' });
}
req.dbStatus = resultado;
next();
} catch (error) {
res.status(500).json({ error: 'Error interno del servidor' });
}
}
app.use(verificarBaseDatos);
Organización de middlewares personalizados
Para mantener el código organizado y reutilizable, es recomendable crear los middlewares en archivos separados:
// middlewares/auth.js
export function requireAuth(req, res, next) {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'Token requerido' });
}
// Lógica de validación del token
req.user = { id: 1, nombre: 'Usuario' };
next();
}
// middlewares/cors.js
export function corsPersonalizado(req, res, next) {
res.header('Access-Control-Allow-Origin', 'https://midominio.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
}
Luego importarlos en nuestra aplicación principal:
import express from 'express';
import { requireAuth } from './middlewares/auth.js';
import { corsPersonalizado } from './middlewares/cors.js';
const app = express();
app.use(corsPersonalizado);
app.use('/api/privada', requireAuth);
app.get('/api/privada/perfil', (req, res) => {
res.json({
mensaje: 'Datos privados del usuario',
usuario: req.user // Disponible gracias al middleware requireAuth
});
});
Esta aproximación nos permite crear middlewares reutilizables que pueden aplicarse selectivamente según las necesidades de cada ruta o grupo de rutas en nuestra aplicación Express.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Express
Documentación oficial de Express
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Express es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Express
Explora más contenido relacionado con Express y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender la estructura básica de un middleware personalizado en Express.
- Aprender a registrar middlewares globales y específicos para rutas.
- Desarrollar middlewares con funcionalidades variadas, incluyendo modificación de objetos req y res.
- Implementar middlewares parametrizados para mayor flexibilidad.
- Manejar middlewares asíncronos y organizar el código en módulos reutilizables.