Manejo de Errores en Express.js

Manejo de Errores en Express.js

El manejo de errores en Express es crucial para crear aplicaciones robustas y predecibles. Permite capturar, procesar y responder a diferentes tipos de errores de manera controlada.

Estructura Avanzada de Manejo de Errores

javascript
// errorHandler.js
class AppError extends Error {
constructor(message, statusCode) {
  super(message);
  this.statusCode = statusCode;
  this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
  this.isOperational = true;

  Error.captureStackTrace(this, this.constructor);
}
}

// Middleware de manejo de errores global
const globalErrorHandler = (err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';

res.status(err.statusCode).json({
  status: err.status,
  message: err.message,
  ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
};

module.exports = { AppError, globalErrorHandler };

Captura de Errores Asíncronos Modernos

javascript
// catchAsync.js - Manejo de errores asíncronos
const catchAsync = (fn) => {
return (req, res, next) => {
  fn(req, res, next).catch(next);
};
};

// Ejemplo de uso
const getUsers = catchAsync(async (req, res, next) => {
const users = await User.find();

if (!users.length) {
  return next(new AppError('No users found', 404));
}

res.status(200).json({
  status: 'success',
  results: users.length,
  data: { users }
});
});

Códigos de Estado HTTP Actualizados

CódigoSignificadoEjemplos Prácticos
200OKSolicitud exitosa
201CreatedRecurso creado
400Bad RequestDatos inválidos o faltantes
401UnauthorizedToken inválido o expirado
403ForbiddenSin permisos suficientes
404Not FoundRecurso no existente
422Unprocessable EntityErrores de validación
500Internal Server ErrorErrores no controlados

Middleware de Validación Integrado

javascript
// validationMiddleware.js
const { body, validationResult } = require('express-validator');

const validate = (validations) => {
return async (req, res, next) => {
  for (let validation of validations) {
    const result = await validation.run(req);
    if (result.errors.length) break;
  }

  const errors = validationResult(req);
  if (errors.isEmpty()) {
    return next();
  }

  return res.status(400).json({
    errors: errors.array()
  });
};
};

// Ejemplo de uso
app.post('/usuarios', 
validate([
  body('email').isEmail().withMessage('Email inválido'),
  body('nombre').notEmpty().withMessage('Nombre requerido')
]),
crearUsuario
);

Registro de Errores con Winston

javascript
const winston = require('winston');

const logger = winston.createLogger({
level: 'error',
format: winston.format.combine(
  winston.format.timestamp(),
  winston.format.json()
),
transports: [
  new winston.transports.File({ filename: 'error.log' })
]
});

// Middleware de registro
const errorLogger = (err, req, res, next) => {
logger.error({
  message: err.message,
  stack: err.stack,
  method: req.method,
  path: req.path
});
next(err);
};
  Consideraciones Finales

  • Mantén la consistencia en el manejo de errores
  • Personaliza respuestas según el entorno
  • Usa bibliotecas como express-validator
  • Implementa registro de errores
  • Separa lógica de manejo de errores