Kodokon kodokon.com

Validación de entradas y middleware de errores

Valida los datos en el borde de la API y centraliza toda la gestión de errores en un único middleware de cuatro parámetros.

9 min · 3 preguntas

Abrir esta lección en Kodokon

Cada dato entrante es hostil hasta que se demuestre lo contrario: cuerpo JSON, parámetros de URL, cabeceras. La validación pertenece al borde de la aplicación, antes del controlador, para que las capas internas trabajen sobre datos garantizados. Después, distingue dos familias de errores: los errores operacionales (entrada inválida, recurso ausente, conflicto), esperados y traducidos a 4xx, y los errores de programación (bugs), que deben producir un 500 opaco del lado del cliente y una traza de pila completa del lado del servidor.

JAVASCRIPT
export class HttpError extends Error {
  constructor(status, message, details = undefined) {
    super(message);
    this.status = status;
    this.details = details;
  }
}
Un error que lleva su estado HTTP: el ladrillo básico.

Un middleware de validación intercepta la petición antes del controlador. La versión manual de abajo muestra el principio; en producción, un esquema declarativo (zod se ha convertido en el estándar) aporta además inferencia de tipos y mensajes estructurados. La contrapartida: una dependencia y un ligero coste en tiempo de ejecución, a cambio de reglas centralizadas, componibles e imposibles de olvidar.

JAVASCRIPT
import { HttpError } from './http-error.js';

export function validateUser(req, res, next) {
  const { email, name } = req.body ?? {};
  const errors = [];
  if (typeof email !== 'string' || !email.includes('@')) {
    errors.push('email: invalid format');
  }
  if (typeof name !== 'string' || name.trim().length < 2) {
    errors.push('name: 2 characters minimum');
  }
  if (errors.length > 0) {
    return next(new HttpError(400, 'Invalid body', errors));
  }
  next();
}
Conéctalo con router.post('/', validateUser, controller.create).

Express reconoce un middleware de errores por su firma de cuatro parámetros (err, req, res, next). Registrado el último, después de todas las rutas con app.use(errorHandler), se convierte en la única salida de errores de la API: un formato de respuesta homogéneo, el logging en un solo lugar, sin fugas de información interna. Los controladores, por su parte, se limitan a llamar a next(err).

JAVASCRIPT
export function errorHandler(err, req, res, next) {
  if (res.headersSent) {
    return next(err);
  }
  const status = err.status ?? 500;
  const body = { error: err.message };
  if (err.details) {
    body.details = err.details;
  }
  if (status >= 500) {
    console.error(err);
    body.error = 'Internal server error';
  }
  res.status(status).json(body);
}
4xx transparente para el cliente, 500 enmascarado pero registrado.

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. ¿Cómo distingue Express un middleware de errores de uno ordinario?
    • Por su nombre, que debe contener la palabra error
    • Por su firma de cuatro parámetros (err, req, res, next)
    • Por su posición al principio de la cadena
    • Por una llamada explícita a app.setErrorHandler
  2. ¿Cuál es la respuesta HTTP correcta ante un error de programación inesperado?
    • Un 500 con el mensaje y la pila para ayudar al diagnóstico
    • Un 400 para indicar que la petición ha fallado
    • Un 500 con un mensaje genérico, registrándose el error completo del lado del servidor
  3. En Express 4, ¿qué ocurre si un handler async se rechaza sin try/catch?
    • El error llega igualmente al middleware de errores
    • La petición queda colgada: el rechazo nunca se reenvía a next
    • Express devuelve automáticamente un 400
    • El proceso Node se detiene de inmediato