Appearance
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 deHttpError(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.
- Captura de errores: Es el último middleware en la cadena de Express que se ejecuta cuando un error es pasado a
- 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 quereqtenga propiedadesemailyuiddespués de que el token sea verificado. - Extracción del token: Busca el encabezado
Authorizationy extrae el token (formatoBearer <token>). - Validación de token: Utiliza
verifyAccessTokenpara 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
emailyuiddel payload del token y los adjunta al objetoreqpara que estén disponibles en los controladores posteriores. - Continuación del flujo: Llama a
next()para pasar la solicitud al siguiente middleware o ruta.
- Extensión de la interfaz
- 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 });