David Mauricio Gorraiz Moreno
Alejandro Ramírez
ProfesorMuy bien, David!
Contar con validaciones automáticas en las APIs es clave para la calidad y seguridad de tus servicios. En este resumen aprenderás cómo aprovechar Spring Boot y las anotaciones de jakarta.validation para controlar los datos que recibe tu aplicación, evitando errores comunes y mejorando la experiencia de quienes consumen tus endpoints.
¿Por qué validar los datos de entrada en APIs es fundamental?
Validar los datos desde el inicio evita que información errónea llegue al núcleo de la lógica de la aplicación. Así, tu API responde de manera constructiva ante intentos de enviar datos incompletos o inconsistentes.
¿Cómo agregar una capa de validación en Spring Boot usando anotaciones?
Se recomienda agregar la dependencia "Validation" en tu proyecto mediante Spring Initializer (start.spring.io). Para ello, busca bean validation with Hibernate Validator o agrega 'Spring Boot Starter Validation' en tu archivo build.gradle y actualiza las dependencias.
Luego, utiliza las anotaciones en el DTO que representa el cuerpo de la petición:
@NotBlank para campos obligatorios que no pueden ser vacíos (ejemplo: título).@PastOrPresent para fechas que no pueden ser futuras (ejemplo: fecha de lanzamiento).@Min y @Max para restringir valores numéricos (ejemplo: rating entre 0 y 5).¿Cómo reportar errores de validación y manejar excepciones en tu API?
Cuando se incumple alguna de estas reglas, Spring lanza una excepción method argument not valid exception. Para manejarla de forma adecuada:
getBindingResult().getFieldErrors() y agrega mensaje y campo a dicho listado.Este enfoque permite que el cliente reciba una lista con los problemas específicos, en vez de una respuesta genérica sin detalles.
Además, es recomendable agregar un manejador general para captar cualquier otra excepción no controlada (mediante @ExceptionHandler(Exception.class)), y responder con un internal server error y un mensaje explicativo. Así, ninguna excepción quedará sin procesar, y siempre sabrás qué está fallando.
¿Qué prácticas adicionales potencian la robustez de tu API con Spring Validation?
¿Ya implementaste validaciones en todos los puntos de entrada de tu servicio? Cuéntanos cómo mejoró la calidad de tus endpoints o comparte tu reto en los comentarios.
David Mauricio Gorraiz Moreno
Alejandro Ramírez
ProfesorMuy bien, David!
Milton Hernan Camacho Quitian
Santiago Andres Castro Cruz
Alejandro Ramírez
ProfesorLo que pasa es que @NotBlank solo funciona con String, y en este caso genre es un enum. Por eso no entra en el MethodArgumentNotValidException sino que lanza una excepción más general, porque la anotación no aplica para ese tipo de dato.
La forma correcta es usar @NotNull(message = "El género es obligatorio") en el enum. Si el campo viniera como String, ahí sí tendría sentido usar @NotBlank.
Quinto Impacto
Coloque esta etiqueta para el estado: @NotNull (message = "El campo 'disponible' es obligatorio") Boolean state
ANDRES ALFONSO MIRA MEJIA
✅
Primero le agrego @Vaid en el metodo post en el MovieController:
@PostMapping public ResponseEntity<MovieDto> add(@RequestBody @Valid MovieDto movieDto){ return ResponseEntity.status(HttpStatus.CREATED).body(this.movieService.add(movieDto)); }
Luego en la clase MovieDto se agregan las validaciones que se quieren implementar:
package com.platzi.play.domain.dto; import com.platzi.play.domain.Genre; import jakarta.validation.constraints.*; import java.time.LocalDate; public record MovieDto( Long id, @NotBlank(message = "La pelicula debe tner un titulo que no sea vacio.") String title, @Positive(message = "El valor de la duracion debe ser un numero positivo") Integer duration, Genre genre, @PastOrPresent(message = "La fecha de lanzamiento debe ser anterior o igual a la actual") LocalDate releaseDate, @Min(value = 0, message = "El valor minimo de calificacion debe ser cero") @Max(value = 5, message = "El valor maximo de la calificacion debe ser cinco") Double rating, Boolean state ) { }
Comparto mi propuesta.
En el método add se agrega la anotación @Valid
@PostMapping public ResponseEntity<MovieDto> add(@RequestBody @Valid MovieDto movieDto){ return ResponseEntity.status(HttpStatus.CREATED).body(this.movieService.add(movieDto)); }
Luego, en MovieDto se agregan las anotaciones de Bean Validation:
package com.platzi.play.domain.dto; import com.platzi.play.domain.Genre; import jakarta.validation.constraints.*; import java.time.LocalDate; public record MovieDto( Long id, @NotBlank(message = "El título es obligatorio") String title, @Positive(message = "La duración de la película debe ser mayor que 0") Integer duration, @NotNull(message = "El género de la película debe ser informado") Genre genre, @PastOrPresent(message = "La fecha de lanzamiento debe ser menor a la fecha actual") LocalDate releaseDate, @Min(value = 0, message = "El rating no puede ser menor que 0") @Max(value = 5, message = "El rating no puede ser mayor que 5") Double rating, @NotNull(message = "El estado debe ser informado") Boolean status ) { }
Funciona de la siguiente manera:
En el MovieController el @Valid en metodo
@PostMapping public ResponseEntity<MovieDto> add(@RequestBody @Valid MovieDto movieDto){ return ResponseEntity.status(HttpStatus.CREATED).body(this.movieService.add(movieDto)); }
y luego de eso ponemos las validaciones en el MovieDto
public record MovieDto( Long id, @NotBlank(message = "El titulo es obligatorio") String title, @Min(value = 1, message = "La duracion no puede ser menor a 1") @Max(value = 240, message = "La duracion no puede ser mayor a 240") Integer duration, Genre genre, @PastOrPresent(message = "la fecha de lanzamiento debe ser anterior a la fecha actual") LocalDate releaseDate, @Min(value = 0, message = "El rating no puede ser menor a 0") @Max(value = 5, message = "El rating no puede ser mayor a 5") Double rating, State state ) { }
de esta forma me funciona, pero tengo una pregunta adicionalmente.
¿Por qué cuando adiciona la
@NotBlank(message = "El genero es obligatorio")
para el genero, me sale la excepción general y no la del MethodArgumentNotValidException
?