Contenido del curso

Endpoint PUT con MapStruct en Spring Boot

Resumen

Actualizar registros es tan común como crearlos, y en una API REST con Spring Boot necesitas un endpoint PUT bien estructurado para hacerlo de forma segura. Aquí aprendes a construir un endpoint PUT que valida la existencia del recurso, controla qué campos se modifican y persiste los cambios usando MapStruct y JPA.

¿Por qué usar un DTO específico para actualizar?

No siempre quieres permitir que se editen todos los campos de un recurso. En el caso de una película, cambiar el género o la duración no tiene sentido, pero sí actualizar el título, la fecha de estreno y el rating.

Por eso conviene crear un UpdateMovieDTO separado del MovieDTO original. Este nuevo objeto solo expone los tres campos editables y deja fuera la clave primaria y los datos que deben permanecer inmutables.

¿Qué es un DTO de actualización? Es un objeto de transferencia de datos que contiene únicamente los campos que el cliente puede modificar. Protege tu modelo de cambios no autorizados y hace explícita la intención del endpoint.

¿Cómo se define el DTO en el código?

Duplicas el MovieDTO existente, lo renombras a UpdateMovieDTO y eliminas los atributos que no quieres exponer: el id, la duración y el género. El resultado es un DTO mínimo con solo tres propiedades [02:00].

¿Cómo construir el endpoint PUT en el controlador?

El controlador recibe dos piezas de información: el id del recurso por la URL y el cuerpo con los nuevos valores. Para eso usas la anotación @PutMapping combinada con @PathVariable y @RequestBody.

La firma queda así: el id viaja como variable de ruta y el UpdateMovieDTO llega en el cuerpo de la petición. El controlador delega la lógica al servicio y devuelve un ResponseEntity.ok con el DTO actualizado.

java @PutMapping("/{id}") public ResponseEntity<MovieDTO> update( @PathVariable Long id, @RequestBody UpdateMovieDTO updateMovieDTO) { return ResponseEntity.ok(movieService.update(id, updateMovieDTO)); }

¿Cómo validar la existencia antes de actualizar?

Antes de modificar cualquier dato, debes confirmar que el recurso existe. La estrategia es buscar el MovieEntity en la base con findById y revisar el resultado [04:30].

Si el entity es null, retornas null porque no hay nada que actualizar. Si existe, aplicas los cambios sobre ese objeto recuperado y luego lo guardas. Este patrón evita crear registros fantasma y garantiza que solo modifiques lo que ya está persistido.

¿Qué pasa si el id no existe en la base de datos? El método retorna null y el cliente puede interpretarlo como recurso no encontrado. Así proteges la integridad de tu base.

¿Cómo usar MapStruct con MappingTarget para actualizar entidades?

Asignar campo por campo con setTítulo, setFechaEstreno y setClasificación funciona, pero ensucia el código. MapStruct ofrece una solución más limpia con la anotación @MappingTarget.

Esta anotación le dice a MapStruct que reciba el objeto por referencia y aplique los mapeos sobre esa misma instancia, sin crear uno nuevo. El método no retorna nada porque modifica el entity in place.

¿Cómo se declara el método en el mapper?

Dentro del MovieMapper defines un método updateEntityFromDTO que recibe el UpdateMovieDTO y el MovieEntity anotado con @MappingTarget. Luego declaras tres @Mapping para enlazar los campos:

  • target título desde source title.
  • target fechaEstreno desde source releaseDate.
  • target clasificación desde source rating.

java void updateEntityFromDTO( UpdateMovieDTO updateMovieDTO, @MappingTarget MovieEntity movieEntity);

¿Qué ventaja tiene el paso por referencia?

Al pasar el MovieEntity por referencia, los cambios se reflejan directamente en el objeto recuperado de la base. No necesitas asignar el resultado a una variable nueva ni hacer conversiones manuales. Una sola línea reemplaza tres setters.

¿Cómo se conecta el repositorio con el servicio?

En el MovieRepository defines el método update que recibe el id y el UpdateMovieDTO y retorna un MovieDTO. La implementación en MovieEntityRepository hace tres cosas en orden: busca por id, aplica el mapper con @MappingTarget y guarda con crudRepository.save [07:15].

Un detalle importante: el campo rating llega como double desde el DTO, pero el entity lo maneja como BigDecimal. Resuelves esa incompatibilidad con BigDecimal.valueOf al asignar el valor.

El servicio expone un método update que simplemente delega al repositorio pasando ambos parámetros. Esa separación de capas mantiene cada clase con una responsabilidad clara.

¿Cómo probar el endpoint en Postman?

Con el servicio reiniciado, lanzas una petición PUT a localhost:8090/platzi-play/movies/91, donde 91 es el id de la película a editar. En el body envías solo los tres campos editables: título, releaseDate y rating.

La respuesta llega con código 200 y al hacer un GET sobre el mismo id verificas que la fecha cambió de 2010-06-25 a 2010-06-29 y el rating subió de 3.5 a 4.5 [10:20]. Los demás campos permanecen intactos, justo como debe comportarse una actualización controlada.

Ahora tu API soporta crear y actualizar recursos como cualquier aplicación moderna. ¿Te animas a implementar el reto del @DeleteMapping para eliminar una película por su id? Déjame tu solución en los comentarios.