Skip to content

Archivos de la Carpeta middleware

La carpeta src/middleware contiene las funciones middleware de Express, que son piezas de código que se ejecutan entre la recepción de una solicitud HTTP y el envío de una respuesta. Estos archivos son fundamentales para realizar tareas transversales como la gestión de errores, la autenticación y la preparación de solicitudes antes de que lleguen a los controladores, asegurando un flujo de aplicación más robusto y seguro.

http.error.handle.middleware.ts

Este middleware se encarga de manejar y estandarizar las respuestas de error HTTP en la aplicación.

  • Descripción: Captura los errores que ocurren durante el procesamiento de las solicitudes, distingue entre errores personalizados (HttpError) y errores genéricos del servidor, y envía una respuesta JSON adecuada al cliente. Además, registra los errores para facilitar la depuración.
  • Propósito: Centralizar y uniformar el manejo de errores en toda la API, proporcionando mensajes de error consistentes al cliente y manteniendo un registro de los fallos internos para monitoreo y depuración.
  • Funcionalidad:
    • Captura de errores: Es el último middleware en la cadena de Express que se ejecuta cuando un error es pasado a next(error).
    • Registro de errores: Utiliza un logger (logger.error) para registrar los detalles del error, incluyendo el método y la URL de la solicitud.
    • Manejo de HttpError: Si el error es una instancia de HttpError (un error definido por la aplicación con un código HTTP específico), responde con el código y mensaje de ese error.
    • Manejo de errores genéricos: Para cualquier otro tipo de error, responde con un código 500 (Internal Server Error) y un mensaje genérico para evitar exponer detalles sensibles al cliente.
  • Rol en la aplicación: Es crucial para la estabilidad y la experiencia del usuario, ya que transforma errores internos y excepciones en respuestas HTTP claras y predecibles. Es la "última línea de defensa" para los errores, garantizando que el cliente nunca reciba una respuesta inesperada o sin formato.
ts
type JsonResponse<T> = {
  statusCode: number;
  body: T;
  headers?: Record<string, string>;
};

export function jsonResponse<T>(
  statusCode: number,
  body: T,
  headers: Record<string, string> = { "Content-Type": "application/json" }
): JsonResponse<T> {
  /*
   * Valida que el statusCode HTTP esté dentro del rango válido (100-599).
   * Si el código es inválido, lanza un error para detener la ejecución.
   */
  if (statusCode < 100 || statusCode > 599) {
    throw new Error("Invalid status code. It must be between 100 and 599.");
  }

  /*
   * Retorna un objeto con la estructura de JsonResponse<T>.
   * Este objeto contiene el código de estado, el cuerpo de la respuesta
   * y los encabezados (por defecto, Content-Type: application/json).
   */
  return {
    statusCode,
    body,
    headers,
  };
}

jwt.middlewares.ts

Este middleware se encarga de la validación de tokens JWT (JSON Web Token) para proteger las rutas de la API.

  • Descripción: Intercepta las solicitudes entrantes, extrae el token de autenticación del encabezado Authorization, lo verifica utilizando una utilidad de seguridad y, si es válido, adjunta la información del usuario (email, uid) a la solicitud (req) antes de pasar el control al siguiente middleware o controlador.
  • Propósito: Asegurar que solo las solicitudes autenticadas y autorizadas puedan acceder a rutas protegidas de la API, validando la identidad del usuario a través de un token JWT.
  • Funcionalidad:
    • Extensión de la interfaz Request: Modifica la interfaz de Express para permitir que req tenga propiedades email y uid después de que el token sea verificado.
    • Extracción del token: Busca el encabezado Authorization y extrae el token (formato Bearer <token>).
    • Validación de token: Utiliza verifyAccessToken para decodificar y validar el token. Si el token es inválido o no se proporciona, responde con un error 401.
    • Inyección de datos de usuario: Si el token es válido, extrae el email y uid del payload del token y los adjunta al objeto req para que estén disponibles en los controladores posteriores.
    • Continuación del flujo: Llama a next() para pasar la solicitud al siguiente middleware o ruta.
  • Rol en la aplicación: Es un componente crítico para la seguridad de la API. Actúa como una "guardia de seguridad" que filtra las solicitudes, asegurando que solo los usuarios legítimos y autenticados puedan acceder a los recursos sensibles, lo que es esencial para la protección de datos y la integridad del sistema.
ts
import { Request, Response, NextFunction } from "express";
import { verifyAccessToken } from "../utils/auth.util";

// Extender o modificar el comportamiento de un módulo ya existente.
// Esto permite añadir propiedades personalizadas al objeto 'Request' de Express.
declare module "express-serve-static-core" {
  interface Request {
    email?: string; // Propiedad para almacenar el email del usuario extraído del token
    uid?: string; // Propiedad para almacenar el ID de usuario extraído del token
  }
}

export const verifyToken = async (
  req: Request, // El objeto de solicitud de Express
  res: Response, // El objeto de respuesta de Express
  next: NextFunction // La función para pasar el control al siguiente middleware
) => {
  // Intenta obtener el encabezado 'authorization' de la solicitud.
  const authHeader = req.headers.authorization;

  /*
   * Si no se proporciona el encabezado de autorización,
   * responde con un estado 401 (Unauthorized) y un mensaje de error.
   * La ejecución se detiene aquí.
   */
  if (!authHeader) {
    res.status(401).json({ error: "No se proporcionó un token" });
    return;
  }

  /*
   * Divide el encabezado de autorización (ej. "Bearer <token>")
   * para extraer solo el token (la segunda parte después de "Bearer ").
   */
  const token = authHeader.split(" ")[1];

  try {
    /*
     * Intenta verificar el token de acceso utilizando la utilidad 'verifyAccessToken'.
     * Si el token es válido, devuelve el payload (datos contenidos en el token).
     */
    const payload = verifyAccessToken(token);

    /*
     * Si el token es válido, extrae el email y el uid del payload
     * y los adjunta al objeto 'req'. Esto hace que el email y el uid
     * estén disponibles para los controladores o middlewares posteriores.
     */
    req.email = payload.email;
    req.uid = payload.uid;

    /*
     * Llama a 'next()' para pasar el control al siguiente middleware
     * o a la función controladora de la ruta, permitiendo que la solicitud continúe.
     */
    next();
  } catch (error) {
    /*
     * Si ocurre un error durante la verificación del token (ej. token expirado, inválido),
     * responde con un estado 401 (Unauthorized) y un mensaje de error.
     */
    res.status(401).json({ error: "Token inválido" });
  }
};

multer.middleware.ts

Este middleware se encarga de manejar y estandarizar las respuestas de error HTTP en la aplicación.

  • Descripción: Configura dónde y cómo se almacenarán los archivos subidos temporalmente en el servidor (en la carpeta uploads/ con un nombre único), y crea una instancia de Multer que puede ser usada como middleware para procesar la subida de un solo archivo.
  • Propósito: Facilitar la gestión de la subida de archivos desde el cliente al servidor, proveyendo una forma eficiente y segura de almacenar temporalmente los archivos antes de su procesamiento posterior (ej. subir a Google Drive).
  • Funcionalidad:
    • multer.diskStorage: Define el motor de almacenamiento para Multer.
      • destination: Especifica la carpeta donde se guardarán los archivos (uploads/).
      • filename: Genera un nombre de archivo único utilizando un timestamp y un número aleatorio, combinado con la extensión original, para evitar colisiones.
    • export const upload = multer({ storage }); : Crea y exporta una instancia de Multer configurada con el almacenamiento definido. Esta instancia puede usarse como middleware (ej., upload.single('nombreDelCampoDeArchivo')) en las rutas de Express.
  • Rol en la aplicación: Es el primer punto de contacto para la subida de archivos. Prepara y gestiona los archivos enviados en las solicitudes HTTP, permitiendo que la aplicación los reciba y los procese de manera ordenada y segura, antes de delegar su manejo a otros servicios (como el de Google Drive).
ts
// multer.middleware.ts
import multer from "multer";
import path from "path"; // Módulo de Node.js para trabajar con rutas de archivos y directorios

// Configuración de Multer para guardar los archivos temporalmente en el servidor.
const storage = multer.diskStorage({
  // 'destination' define la carpeta donde se guardarán los archivos subidos.
  destination: "uploads/",

  // 'filename' es una función que determina el nombre del archivo dentro de la carpeta de destino.
  filename: (req, file, cb) => {
    // Genera un sufijo único usando la fecha actual y un número aleatorio grande.
    const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);

    /*
     * Llama al callback (cb) con:
     * - null para indicar que no hay error.
     * - El nombre de archivo final: 'nombreDelCampoDeArchivo' + '-' + 'sufijoUnico' + '.extensionOriginal'.
     * Esto asegura que cada archivo subido tenga un nombre único para evitar colisiones.
     */
    cb(
      null,
      file.fieldname + "-" + uniqueSuffix + path.extname(file.originalname)
    );
  },
});

// Middleware de Multer configurado con el almacenamiento definido.
// 'export const upload' es la instancia de Multer que se usará en las rutas de Express.
// Por ejemplo, `upload.single('miCampoDeArchivo')` manejaría un archivo llamado 'miCampoDeArchivo'.
export const upload = multer({ storage });