Saltar al contenidoPedro Farbo
Lección 7 / 2540 min

Tratamiento de Errores

Tratamiento de Errores

Un sistema robusto de manejo de errores es esencial para APIs en producción.

Clase de Error Personalizada

typescript
// src/errors/AppError.tsexport class AppError extends Error {  public readonly statusCode: number;  public readonly isOperational: boolean;   constructor(message: string, statusCode: number = 400) {    super(message);    this.statusCode = statusCode;    this.isOperational = true;    Error.captureStackTrace(this, this.constructor);  }}

Middleware Global de Errores

typescript
// src/middlewares/error.middleware.tsimport { Request, Response, NextFunction } from 'express';import { AppError } from '../errors/AppError';import { ZodError } from 'zod'; export const errorHandler = (  err: Error,  req: Request,  res: Response,  next: NextFunction) => {  // Errores de validación Zod  if (err instanceof ZodError) {    return res.status(400).json({      status: 'error',      message: 'Error de validación',      errors: err.errors,    });  }   // Nuestros errores personalizados  if (err instanceof AppError) {    return res.status(err.statusCode).json({      status: 'error',      message: err.message,    });  }   // Log de errores inesperados  console.error('Error inesperado:', err);   // No exponer detalles en producción  return res.status(500).json({    status: 'error',    message: process.env.NODE_ENV === 'production'      ? 'Error interno del servidor'      : err.message,  });};

Uso en Services

typescript
// src/services/product.service.tsimport { AppError } from '../errors/AppError'; export class ProductService {  async findById(id: string) {    const product = await prisma.product.findUnique({ where: { id } });     if (!product) {      throw new AppError('Producto no encontrado', 404);    }     return product;  }   async create(data: CreateProductDTO) {    const exists = await prisma.product.findFirst({      where: { name: data.name },    });     if (exists) {      throw new AppError('Ya existe un producto con este nombre', 409);    }     return prisma.product.create({ data });  }}

Async Handler

typescript
// src/utils/async-handler.tsimport { Request, Response, NextFunction } from 'express'; export const asyncHandler = (fn: Function) => {  return (req: Request, res: Response, next: NextFunction) => {    Promise.resolve(fn(req, res, next)).catch(next);  };}; // Usorouter.get('/:id', asyncHandler(async (req, res) => {  const product = await productService.findById(req.params.id);  res.json(product);}));

Handler 404

typescript
// Después de todas las rutasapp.use((req, res) => {  res.status(404).json({    status: 'error',    message: `Ruta ${req.method} ${req.path} no encontrada`,  });}); // Error handler siempre al finalapp.use(errorHandler);

Resumen

  • ✅ Clase AppError personalizada
  • ✅ Middleware de errores centralizado
  • ✅ Manejo de errores async
  • ✅ Logging y respuestas según ambiente

Próxima clase: Introducción a Bases de Datos! 🚀

¿Te gustó el contenido? ¡Tu contribución ayuda a mantener todo online y gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e