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ódigouso
200éxito
201creado
400petición incorrecta
401no autorizado
403acceso prohibido
404recurso no encontrado
500error 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...