Crear un endpoint POST en Spring Boot es el paso que transforma una API de solo lectura en una API funcional capaz de recibir información y persistirla en base de datos. Aquí aprenderás a construir ese endpoint usando @PostMapping, @RequestBody, MapStruct y Spring Data, aplicado a un caso real: registrar películas en Platzi Play.
¿Qué hace un endpoint POST en una API REST?
Un endpoint POST recibe datos en el cuerpo de la petición y los guarda como un nuevo recurso. A diferencia del GET, que solo consulta, el POST modifica el estado del servidor creando registros nuevos.
¿Qué diferencia hay entre GET y POST en Spring Boot? GET se usa con @GetMapping para consultar datos y no envía cuerpo. POST se usa con @PostMapping para enviar información en el cuerpo de la petición y crear nuevos recursos.
¿Cómo defino el método en el controlador?
Dentro de MovieController añades un método que retorna ResponseEntity<MovieDTO> y lo llamas add. Recibe un MovieDTO como parámetro, anotado con @RequestBody, que le indica a Spring que ese objeto viene en el cuerpo de la petición.
La anotación @PostMapping sin valor adicional hereda la ruta del controlador, en este caso /movies. Cuando llegue una petición POST a esa ruta, Spring entra por este método.
java
@PostMapping
public ResponseEntity<MovieDTO> add(@RequestBody MovieDTO movie) {
return ResponseEntity
.status(HttpStatus.CREATED)
.body(this.movieService.add(movie));
}
¿Cómo conecto el controlador con el repositorio?
El flujo va del controlador al servicio, del servicio al repositorio y del repositorio a la base de datos. Cada capa tiene una responsabilidad clara.
¿Cómo convierto un DTO a una entidad con MapStruct?
El repositorio de Spring Data, a través de CrudRepository, expone un método save que recibe una entidad, no un DTO. Necesitas convertir el MovieDTO en MovieEntity antes de guardar.
En MovieMapper creas un método toEntity que recibe un DTO y retorna una entidad. Para evitar reescribir todos los mappings, usas la anotación @InheritInverseConfiguration de MapStruct, que invierte automáticamente la configuración existente: lo que era target pasa a ser source y viceversa.
El único campo que requiere atención manual es el género, porque MapStruct no sabe qué qualifiedByName aplicar. Le indicas explícitamente que use genreToString para convertir el enum en texto.
¿Qué hace @InheritInverseConfiguration en MapStruct? Hereda la configuración de un mapping inverso ya definido. Si tienes un toDTO, te ahorra escribir manualmente el toEntity invirtiendo source y target automáticamente.
¿Cómo manejo campos como ID y estado al guardar?
Dentro del método save del repositorio implementas la lógica: conviertes el DTO en entidad, asignas valores por defecto y luego conviertes el resultado de vuelta a DTO para retornarlo.
- El estado se asigna manualmente como
"D" de disponible, porque no llega en el cuerpo de la petición.
- El ID no se asigna desde el código, ya que la base de datos lo genera automáticamente.
- Después de llamar a
this.crud.save(entity), el resultado se mapea de nuevo a DTO con el ID ya asignado.
Un detalle interesante de MapStruct: si un campo tiene el mismo nombre en el DTO y en la entidad, como id en ambos lados, no necesitas declararlo en el mapper. La librería lo detecta y lo mapea automáticamente.
¿Por qué retornar HttpStatus.CREATED en vez de 200?
Devolver el código correcto es parte de diseñar una API REST profesional. Cuando creas un recurso nuevo, el código adecuado es 201 Created, no 200 OK.
En el controlador usas ResponseEntity.status(HttpStatus.CREATED).body(...). El enum HttpStatus de Spring Framework contiene todos los códigos HTTP disponibles, lo que hace tu código más legible y menos propenso a errores que escribir números mágicos.
Una alternativa es ResponseEntity.created(uri), pero ese método exige pasar una URI del recurso recién creado. Si no la tienes a mano, usar status(HttpStatus.CREATED) es la forma más general y práctica.
¿Cómo pruebo el endpoint POST?
El navegador no envía peticiones POST por defecto, así que necesitas una herramienta como Postman para probarlo.
- Configura una petición POST a
localhost:8090/platzi-play/api/movies.
- En la pestaña Body selecciona raw y formato JSON.
- Envía un objeto con título, duración, género, fecha de lanzamiento y rating.
Ejemplo de cuerpo enviado:
{
"title": "Son como niños",
"duration": 102,
"genre": "COMEDIA",
"releaseDate": "2010-06-25",
"rating": 3.5
}
La respuesta llega con status 201 y el ID generado, por ejemplo el 91. Si haces un GET a /movies/91, recuperas la película recién insertada. Si consultas todas las películas, aparece al final del listado.
¿Qué sigue después de POST?
Ya puedes crear registros, pero las APIs reales también necesitan actualizar datos existentes. El siguiente paso es construir un endpoint PUT que permita editar películas ya guardadas de forma segura y controlada.
¿Qué endpoint te gustaría implementar después: PUT para actualizar o DELETE para eliminar? Cuéntame en los comentarios cómo estás estructurando tu API.