Saltar al contenido

Lección 5 de 12 · Lectura y práctica

Creación y uso de middlewares en Express

CONCEPTO CLAVE: Los middlewares en Express son funciones que tienen acceso al objeto de solicitud (req), al objeto de respuesta (res) y al siguiente middleware en el ciclo de solicitud-respuesta de la aplicación. Son.

Del concepto a la práctica

Taller de esta lección

Un middleware puede añadir contexto sin decidir el resultado final. En un museo, registrar el método y la ruta ayuda a rastrear una petición, mientras que otro middleware puede exigir una cabecera para una zona interna. El orden importa: el parser debe ejecutarse antes de leer JSON y una comprobación debe estar montada antes de la ruta protegida.

Ejemplo resuelto

function auditoria(req,res,next){ req.inicio = Date.now(); next(); } permite que la ruta use el dato. Otro middleware puede comprobar req.get('x-sala'); si falta, responde 400, y si existe llama a next(). Montados como app.use(auditoria) y app.use('/interno', requiereSala), afectan a ámbitos distintos. La cabecera x-sala solo ilustra validación: cualquier cliente puede inventarla, por lo que no autentica usuarios ni protege una zona real.

Pruébalo

  1. Añade un middleware que cuente solicitudes en memoria local.

  2. Añade requiereSala solo bajo /interno.

  3. Envía una petición con y sin x-sala.

  4. Comprueba que cada petición termina en respuesta o en next().

Error frecuente: olvidar next() en la rama válida. Corrígelo retornando next() tras la comprobación; si no, la petición queda esperando hasta agotar el tiempo.

Comprueba tu resultado

Una petición pública debe conservar su respuesta normal. La ruta interna sin cabecera debe devolver 400 y no ejecutar su controlador. Con la cabecera, el controlador debe ejecutarse una vez y el contador debe aumentar una sola unidad.

Navegador, API y base de datos conectados por solicitudes, consultas y respuestas en sentidos opuestos.
CursaloMapa de práctica
Del navegador a los datos

El navegador envía una solicitud a la API. El servidor valida la operación y consulta los datos; después devuelve una respuesta que el navegador puede mostrar. La base de datos se comunica con el servidor y no directamente con el navegador.

Ver la infografía en tamaño completo ↗
CONCEPTO CLAVE: Los middlewares en Express son funciones que tienen acceso al objeto de solicitud (req), al objeto de respuesta (res) y al siguiente middleware en el ciclo de solicitud-respuesta de la aplicación. Son fundamentales para modularizar la lógica de procesamiento de peticiones en una API REST.

Creación y Uso de Middlewares en Express

En el desarrollo de APIs RESTful con Node.js y Express, los middlewares constituyen uno de los conceptos más poderosos y versátiles del framework. Permiten crear capas de procesamiento que se ejecutan de forma secuencial, facilitando la separación de preocupaciones y la reutilización de código.

¿Qué es un Middleware?

Un middleware es esencialmente una función que recibe tres parámetros: request, response y next. Cada middleware puede:

  • Ejecutar cualquier código.
  • Realizar cambios en los objetos request y response.
  • Terminar el ciclo de solicitud-respuesta.
  • Llamar al siguiente middleware en la pila.
📌 Recuerda: El orden de definición de los middlewares en Express importa enormemente. Se ejecutan en el orden en que se definen, por lo que debes estructurarlos cuidadosamente.

Tipos de Middlewares en Express

Tipo Descripción Ejemplo de uso
Integrado Incluido con Express express.json(), express.static()
De terceros Instalados via npm morgan, cors, helmet
Nivel de aplicación Aplica a todas las rutas Autenticación global
Nivel de router Aplica a rutas específicas Middleware por grupo de rutas
Nivel de manejo de errores Con firma de 4 parámetros Gestión centralizada de errores

Creando tu Primer Middleware Personalizado

Veamos cómo crear un middleware desde cero. Empezaremos con un ejemplo sencillo que registre información de cada petición:

// middleware/logger.js
const loggerMiddleware = (req, res, next) => {
  const timestamp = new Date().toISOString();
  const method = req.method;
  const url = req.originalUrl;
  
  console.log(`[${timestamp}] ${method} ${url}`);
  
  // No olvides llamar a next() para continuar
  next();
};

module.exports = loggerMiddleware;
💡 Consejo práctico: Siempre verifica que tu middleware llame a next() o envie una respuesta. Olvidar esto provocará que la petición quede colgada indefinidamente.

Aplicando Middlewares en tu Aplicación

Ahora veamos cómo usar este middleware en tu servidor Express:

// app.js
const express = require('express');
const loggerMiddleware = require('./middleware/logger');

const app = express();

// Middleware a nivel de aplicación - se ejecuta en TODAS las peticiones
app.use(loggerMiddleware);

// También puedes pasar opciones a tu middleware
app.use('/api', loggerMiddleware);

app.get('/users', (req, res) => {
  res.json({ users: [] });
});

app.listen(3000, () => {
  console.log('Servidor corriendo en puerto 3000');
});

Middlewares con Parámetros

A veces necesitas que tu middleware acepte configuraciones. Para esto, puedes factory functions:

// middleware/validateAuth.js
const validateAuth = (options = {}) => {
  const { required = true, roles = [] } = options;
  
  return (req, res, next) => {
    const token = req.headers.authorization;
    
    if (!token && required) {
      return res.status(401).json({ 
        error: 'Token de autenticación requerido' 
      });
    }
    
    // Lógica de validación aquí...
    
    req.user = { id: 1, role: 'admin' }; // Simulación
    next();
  };
};

module.exports = validateAuth;

// Uso:
app.get('/admin', validateAuth({ roles: ['admin'] }), (req, res) => {
  res.json({ message: 'Zona administrativa' });
});
📌 Patrón Factory: Este patrón de crear funciones que retornan middlewares es extremadamente útil para crear middlewares configurables y reutilizables.

Middlewares de Validación de Datos

Un caso de uso muy común es la validación de datos de entrada. Veamos un middleware para validar el cuerpo de una solicitud:

// middleware/validateUser.js
const validateUser = (req, res, next) => {
  const { name, email, password } = req.body;
  const errors = [];
  
  // Validar nombre
  if (!name || typeof name !== 'string' || name.length < 2) {
    errors.push('El nombre debe tener al menos 2 caracteres');
  }
  
  // Validar email con expresión regular
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!email || !emailRegex.test(email)) {
    errors.push('Email inválido');
  }
  
  // Validar contraseña
  if (!password || password.length < 8) {
    errors.push('La contraseña debe tener al menos 8 caracteres');
  }
  
  if (errors.length > 0) {
    return res.status(400).json({ errors });
  }
  
  next();
};

// Uso en ruta
app.post('/users', validateUser, (req, res) => {
  // Aquí ya sabes que los datos son válidos
  const user = req.body;
  res.status(201).json({ message: 'Usuario creado', user });
});
  1. Define el middleware con acceso a req, res y next.
  2. Extrae los datos a validar del objeto request.
  3. Aplica tus reglas de validación.
  4. Si hay errores, responde inmediatamente con status 400.
  5. Si todo está bien, llama a next() para continuar.

Middlewares Asíncronos

En aplicaciones reales, frecuentemente necesitarás realizar operaciones asíncronas dentro de tus middlewares:

// middleware/checkDatabase.js
const checkDatabase = async (req, res, next) => {
  try {
    // Simulación de consulta a base de datos
    const dbConnected = await verifyDatabaseConnection();
    
    if (!dbConnected) {
      return res.status(503).json({ 
        error: 'Servicio de base de datos no disponible' 
      });
    }
    
    req.dbConnected = true;
    next();
  } catch (error) {
    next(error); // Pasa el error al siguiente middleware de errores
  }
};

module.exports = checkDatabase;
⚠️ Importante: Si tu middleware es asíncrono y ocurre un error, debes pasarlo a next(error). Express lo capturará y lo enviará al middleware de manejo de errores.

Middleware de Manejo de Errores

Express tiene un tipo especial de middleware con cuatro parámetros que se encarga de manejar errores:

// middleware/errorHandler.js
const errorHandler = (err, req, res, next) => {
  console.error('Error:', err.stack);
  
  const statusCode = err.statusCode || 500;
  const message = err.message || 'Error interno del servidor';
  
  res.status(statusCode).json({
    error: {
      message,
      status: statusCode,
      timestamp: new Date().toISOString(),
      path: req.path
    }
  });
};

module.exports = errorHandler;

// Uso - debe ser el ÚLTIMO middleware registrado
app.use(errorHandler);
Un middleware de manejo de errores debe tener siempre cuatro parámetros. Express reconoce esta firma especial y sabe que se trata de un handler de errores.

Encadenando Middlewares

Puedes aplicar múltiples middlewares a una misma ruta. Se ejecutarán en orden:

app.post(
  '/products',
  validateProduct,      // 1. Valida los datos
  checkPermissions,    // 2. Verifica permisos del usuario
  checkDatabase,       // 3. Verifica conexión a BD
  async (req, res) => { // 4. Handler final
    const product = await ProductService.create(req.body);
    res.status(201).json(product);
  }
);

Middlewares de Terceros Útiles

Ver más

Existen muchos middlewares populares que puedes instalar via npm:

  • morgan: Logger HTTP para desarrollo y producción.
  • cors: Habilita CORS (Cross-Origin Resource Sharing).
  • helmet: Configura headers de seguridad HTTP.
  • express-rate-limit: Limita las solicitudes repetidas.
  • express-validator: Validación y sanitización de datos.
// Instalación
npm install morgan cors helmet express-rate-limit

// Uso básico
const morgan = require('morgan');
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

app.use(morgan('dev'));
app.use(cors());
app.use(helmet());

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutos
  max: 100 // límite de 100 solicitudes por ventana
});
app.use('/api', limiter);

Organización de Middlewares

Para proyectos grandes, organiza tus middlewares en carpetas temáticas:

/src
  /middleware
    /auth
      validateToken.js
      requireRole.js
    /validation
      validateUser.js
      validateProduct.js
    /security
      rateLimiter.js
      cors.js
    /logging
      logger.js
      requestId.js
    errorHandler.js
  app.js
💡 Best Practice: Mantén tus middlewares pequeños y con una única responsabilidad. Si un middleware hace demasiadas cosas, divídelo en múltiples middlewares más pequeños.

Resumen Práctico

Patrón Sintaxis Uso
Básico (req, res, next) => {} Logging, parsing simple
Con opciones (options) => (req, res, next) => {} Configuraciones dinámicas
De errores (err, req, res, next) => {} Manejo centralizado de errores
Async async (req, res, next) => {} Operaciones con BD o APIs externas

Los middlewares son el alma de Express. Dominar su uso te permitirá crear APIs robustas, mantenibles y escalables. Practica creando tus propios middlewares y verás cómo tu código se vuelve mucho más limpio y modular.

🧠 Quiz

¿Cuál es el orden correcto de los parámetros en un middleware de manejo de errores de Express?

  • A) req, res, next, error
  • B) error, req, res, next
  • C) req, error, res, next
  • D) next, req, res, error
✅ Respuesta correcta: B. Los middlewares de manejo de errores siempre reciben (error, req, res, next) como parámetros. Express identifica este middleware por su firma de cuatro parámetros.
🧠 Quiz

¿Qué sucede si un middleware no llama a next() ni envía una respuesta?

  • A) El servidor se reinicia automáticamente
  • B) La petición queda colgada indefinidamente
  • C) Express ignora el middleware automáticamente
  • D) Se genera un error 500 inmediatamente
✅ Respuesta correcta: B. Si un middleware no llama a next() ni envía una respuesta (res.send(), res.json(), etc.), la solicitud quedará esperando indefinidamente, causando un memory leak y eventualmente un timeout.

Sigue con Construcción de APIs RESTful con Node.js y Express

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.