Curso de Spring Boot
En una aplicación real siempre ocurren errores.
Por ejemplo:
- un usuario no existe
- datos inválidos
- error en base de datos
- petición incorrecta
Es muy importante manejar los errores correctamente para que la API devuelva respuestas claras.
En este capítulo veremos:
- excepciones en Spring
- crear excepciones personalizadas
- manejo global de errores
- respuestas de error profesionales
9.1 Qué ocurre si no manejamos errores
Supongamos este código:
1@GetMapping("/users/{id}") 2public User getUser(@PathVariable Long id) { 3 4 return repository.findById(id).get(); 5 6}
Si el usuario no existe ocurrirá un error.
Respuesta típica:
1{ 2 "timestamp": "...", 3 "status": 500, 4 "error": "Internal Server Error" 5}
Este mensaje no es claro para el cliente.
9.2 Crear excepciones personalizadas
Es mejor crear nuestras propias excepciones.
Ejemplo
1public class UserNotFoundException extends RuntimeException { 2 3 public UserNotFoundException(String message) { 4 super(message); 5 } 6 7}
9.3 Usar la excepción en el service
1public User getUser(Long id) { 2 3 return repository.findById(id) 4 .orElseThrow(() -> new UserNotFoundException("Usuario no encontrado")); 5 6}
Si el usuario no existe se lanzará esta excepción.
9.4 Manejo global de errores
Para capturar excepciones usamos:
1@ControllerAdvice
Esto permite manejar errores en toda la aplicación.
9.5 Crear un manejador de errores
1@ControllerAdvice 2public class GlobalExceptionHandler { 3 4}
9.6 Manejar una excepción específica
Ejemplo:
1@ExceptionHandler(UserNotFoundException.class) 2public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) { 3 4 return ResponseEntity 5 .status(HttpStatus.NOT_FOUND) 6 .body(ex.getMessage()); 7 8}
Resultado
Petición:
1GET /users/10
Respuesta:
1404 Not Found 2Usuario no encontrado
9.7 Manejar múltiples excepciones
Podemos manejar diferentes errores.
Ejemplo:
1@ExceptionHandler(Exception.class) 2public ResponseEntity<String> handleGeneralError(Exception ex) { 3 4 return ResponseEntity 5 .status(HttpStatus.INTERNAL_SERVER_ERROR) 6 .body("Error interno del servidor"); 7 8}
Esto captura errores inesperados.
9.8 Crear un objeto de error
En APIs profesionales es mejor devolver errores estructurados.
Clase ErrorResponse
1public class ErrorResponse { 2 3 private int status; 4 private String message; 5 private String timestamp; 6 7}
9.9 Respuesta de error estructurada
Ejemplo de respuesta:
1{ 2 "status": 404, 3 "message": "Usuario no encontrado", 4 "timestamp": "2026-01-10T12:00:00" 5}
Esto es mucho más profesional.
9.10 Implementación
1@ExceptionHandler(UserNotFoundException.class) 2public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) { 3 4 ErrorResponse error = new ErrorResponse(); 5 6 error.setStatus(404); 7 error.setMessage(ex.getMessage()); 8 error.setTimestamp(LocalDateTime.now().toString()); 9 10 return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error); 11 12}
9.11 Manejar errores de validación
Cuando usamos @Valid, Spring lanza:
1MethodArgumentNotValidException
Podemos capturarlo.
Ejemplo
1@ExceptionHandler(MethodArgumentNotValidException.class) 2public ResponseEntity<Map<String,String>> handleValidation( 3 MethodArgumentNotValidException ex) { 4 5 Map<String,String> errors = new HashMap<>(); 6 7 ex.getBindingResult().getFieldErrors() 8 .forEach(error -> 9 errors.put(error.getField(), error.getDefaultMessage())); 10 11 return ResponseEntity.badRequest().body(errors); 12 13}
9.12 Ejemplo respuesta de validación
1{ 2 "name": "El nombre es obligatorio", 3 "email": "Email inválido" 4}
Esto facilita mucho el trabajo del frontend.
9.13 Códigos HTTP recomendados
| código | uso |
|---|---|
| 200 | éxito |
| 201 | creado |
| 400 | petición incorrecta |
| 401 | no autorizado |
| 403 | acceso prohibido |
| 404 | recurso no encontrado |
| 500 | error servidor |
9.14 Ejemplo completo
Excepción
1public class UserNotFoundException extends RuntimeException { 2 3 public UserNotFoundException(String message) { 4 super(message); 5 } 6 7}
Service
1public User getUser(Long id) { 2 3 return repository.findById(id) 4 .orElseThrow(() -> new UserNotFoundException("Usuario no encontrado")); 5 6}
Handler
1@ControllerAdvice 2public class GlobalExceptionHandler { 3 4 @ExceptionHandler(UserNotFoundException.class) 5 public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) { 6 7 return ResponseEntity.status(404).body(ex.getMessage()); 8 9 } 10 11}
9.15 Buenas prácticas
Nunca devolver errores genéricos
❌
1Error interno
✔
1Usuario no encontrado
Usar excepciones específicas
Ejemplo:
1UserNotFoundException 2OrderNotFoundException
Usar manejo global
Evita repetir código en controllers.
- Loading...