Skip to content

Errores de dominio

Los errores de negocio viven en el dominio y se propagan hasta HTTP mediante un filtro global. El dominio no conoce status codes: solo lanza errores tipados; la infraestructura los traduce.

text
use case / domain
        │  throw new UserNotFoundError(...)

DomainErrorFilter          (infrastructure, global)
        │  DomainErrorToHttpStatusCode[code]

HTTP JSON { statusCode, error, message }

Piezas base (src/shared)

PiezaRol
DomainErrorClase base (message + code)
DomainErrorCodeCódigos estables (INVALID_UUID_FORMAT, …) — orden alfabético
DomainErrorFilter@Catch(DomainError) → respuesta HTTP JSON
DomainErrorToHttpStatusCodeMapa DomainErrorCode → status HTTP — orden alfabético

Dónde crear un error nuevo

Cada error concreto vive dentro de su bounded context, en domain/errors/:

text
src/
└── users/
    └── domain/
        └── errors/
            └── UserNotFoundError.ts

No coloques errores de un módulo en shared salvo que sean realmente transversales (la base DomainError / DomainErrorCode sí).

Nomenclatura

  • Clase y archivo: PascalCase, nombre descriptivo del fallo de negocio, siempre terminado en Error.
    • UserNotFoundError, OrderAlreadyCancelledError, InsufficientBalanceError
    • Error1, UserError, NotFound (sin sufijo / demasiado genérico)
  • Código en DomainErrorCode: SCREAMING_SNAKE_CASE alineado con el significado (USER_NOT_FOUND, ORDER_ALREADY_CANCELLED, …).
  • Un archivo = un error (UserNotFoundError.ts exporta UserNotFoundError).

Checklist al añadir un error

  1. Crear src/<context>/domain/errors/<NombreDescriptivo>Error.ts extendiendo DomainError.
  2. Añadir el código en DomainErrorCode (orden alfabético).
  3. Mapear el código a un status HTTP en DomainErrorToHttpStatusCode (orden alfabético).
  4. Lanzarlo desde domain/application; el filtro global se encarga del resto.

Ejemplo

typescript
// src/users/domain/errors/UserNotFoundError.ts
import { DomainError } from '../../../shared/domain/errors/DomainError'
import { DomainErrorCode } from '../../../shared/domain/errors/DomainErrorCode'

export class UserNotFoundError extends DomainError {
  constructor(userId: string) {
    super(`User ${userId} was not found`, DomainErrorCode.USER_NOT_FOUND)
  }
}

Forma de respuesta HTTP

json
{
  "statusCode": 400,
  "error": "INVALID_UUID_FORMAT",
  "message": "..."
}

Guía de status

Tipo de falloHTTP típico
Validación / input inválido400
No autenticado401
Prohibido403
No encontrado404
Conflicto / ya existe409
Inesperado / bug500

MIT License · Scaffold from backend-boiler