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)
| Pieza | Rol |
|---|---|
DomainError | Clase base (message + code) |
DomainErrorCode | Códigos estables (INVALID_UUID_FORMAT, …) — orden alfabético |
DomainErrorFilter | @Catch(DomainError) → respuesta HTTP JSON |
DomainErrorToHttpStatusCode | Mapa 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.tsNo 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_CASEalineado con el significado (USER_NOT_FOUND,ORDER_ALREADY_CANCELLED, …). - Un archivo = un error (
UserNotFoundError.tsexportaUserNotFoundError).
Checklist al añadir un error
- Crear
src/<context>/domain/errors/<NombreDescriptivo>Error.tsextendiendoDomainError. - Añadir el código en
DomainErrorCode(orden alfabético). - Mapear el código a un status HTTP en
DomainErrorToHttpStatusCode(orden alfabético). - 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 fallo | HTTP típico |
|---|---|
| Validación / input inválido | 400 |
| No autenticado | 401 |
| Prohibido | 403 |
| No encontrado | 404 |
| Conflicto / ya existe | 409 |
| Inesperado / bug | 500 |