Express

Express

Tutorial Express: Middlewares personalizados

Aprende a crear middlewares personalizados en Express para gestionar peticiones HTTP con funciones específicas y reutilizables.

Aprende Express y certifícate

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.

Aprende Express online

Otras lecciones de Express

Accede a todas las lecciones de Express y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a Express y certifícate

Ejercicios de programación de Express

Evalúa tus conocimientos de esta lección Middlewares personalizados con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.