Manejo de errores
Ahora que tenemos el logging en su lugar, abordemos otro cross-cutting concern. Ahí afuera te vas a encontrar con muchos escenarios como el siguiente:
-
service.com/users/-1devuelve:{"errorDescription": "User not found","cause": "BAD REQUEST"} -
pero
service.com/product/-1devuelve:{"message": "not found","error": 404}
La consistencia se fue por la ventana ahí, y se pone peor con errores dentro de 200OK. No queremos ser ese tipo de dev: vamos a hacer un manejo de errores apropiado.
Manejo de errores
@RestControllerAdvice actúa como un "coordinador de errores" central para tu aplicación.
- Es un lugar único donde podés definir cómo todos los errores, excepciones, o escenarios inesperados se traducen en respuestas.
- En lugar de esparcir la lógica de manejo de errores por cada controlador, esta herramienta asegura que cada error, ya sea de una búsqueda de usuario, búsqueda de producto, o bug interno, siga las mismas reglas y formato.
Problem Details for HTTP APIs es una "plantilla de error" estandarizada que estructura respuestas de forma clara y consistente. Pensalo como un formulario pre-diseñado que cada error completa:
- Qué tipo de error ocurrió (por ejemplo, "film_not_found")
- Un título legible por humanos (por ejemplo, "Resource Not Found")
- El código de estado HTTP (por ejemplo, 404)
- Detalles adicionales (por ejemplo, "Film ID -1 does not exist")
Juntas, estas herramientas aseguran que tu app nunca confunda a los clientes con formatos de error dispares. Incluso casos edge o errores no anticipados se envuelven en la misma estructura predecible.
- Java
- Kotlin
- Groovy
Creá la clase @RestControllerAdvice
- Java
- Kotlin
- Groovy
Si visitás una uri que no existe (como http://localhost:8080), ahora vas a obtener un error estandarizado:
curl -s http://localhost:8080 | jq; curl -sw "→ HTTP %{http_code}\n" -o /dev/null http://localhost:8080
{
"detail": "No static resource for request '/'.",
"instance": "/",
"status": 404,
"title": "Not Found",
"timestamp": "2026-01-11T20:16:13.240960834Z",
"trace": "d9178227-18d6-4442-8598-9a9f17f65f9c"
}
→ HTTP 404
Esto es lo que pasa por detrás:
Handlers comunes que podés necesitar
Si ocurre una excepción que no es manejada por ningún @ExceptionHandler específico en tu @RestControllerAdvice, va a caer en el @ExceptionHandler(Exception.class) default que retorna una respuesta genérica de 500 Internal Server Error.
Acá están las excepciones más comunes que vas a querer manejar explícitamente:
| Excepción | Descripción | Ejemplo | Notas |
|---|---|---|---|
ConstraintViolationException | Parámetros/campos de request fallan validación (@NotNull, @Size, @Pattern) | Request body faltando un campo requerido | Requiere Jakarta EE (para agregar después) |
MethodArgumentTypeMismatchException | Parámetro de request no puede ser convertido al tipo esperado | Controlador espera Integer pero recibe String | |
NoResourceFoundException | Request accede a un recurso Spring MVC inexistente | Accediendo a un endpoint indefinido | |
NoSuchElementException | Optional.get() llamado sobre un Optional vacío | Buscando un usuario inexistente por ID | |
PropertyReferenceException | Propiedad inválida usada en query de repositorio Spring Data | Ordenando por un campo inexistente | Requiere Spring Data (para agregar después) |
A medida que tu app crezca, tené esta tabla a mano — probablemente vuelvas a ella cada vez que agregues un nuevo endpoint o modelo de dominio.