CRUD = Create, Read, Update, Delete. Es el pan de cada día de cualquier backend que gestione datos — desde una app de recetas hasta el sistema que guarda tu carrito de compras. Ya tienes la parte de Read (nivel 1-2, dada como ejemplo). En este nivel completas Create, Update y Delete: las tres letras que faltan para tener una API que de verdad hace algo, no solo mira.
Antes de tocar el controller, completa
RecipeService.toEntity(RecipeDTO dto).
Este método convierte lo que llega del cliente (RecipeDTO, campos simples:
String, List<String>) a la entidad que se persiste (Recipe, con
objetos Chef, Ingredient, Step).
Fíjate en la jerarquía de Chef (carpeta model/): es una clase abstracta
con tres subclases (Contestant, Judge, Viewer). El campo
dto.getChefType() (un String) te dice cuál construir:
switch (dto.getChefType()) {
case "Contestant": chef = new Contestant(nombre, temporada); break;
case "Judge": chef = new Judge(nombre); break;
default: chef = new Viewer(nombre); // Viewer y cualquier valor desconocido
}Esto es un ejemplo real de polimorfismo: el resto del código (por
ejemplo toDTO, que ya está implementado) trabaja con la referencia
Chef sin preocuparse de si es un Contestant, Judge o Viewer — como
un mesero que atiende a "un cliente" sin necesitar saber si esa persona es
programador, doctor o astronauta: el trato es el mismo, el comportamiento
específico de cada uno no le importa a este método.
Compara con toDTO(Recipe recipe), en el mismo archivo, que hace la
conversión inversa y ya está completo — es tu referencia.
Con toEntity funcionando, completa en RecipeController.java:
POST /api/recipes(createRecipe): convierte el DTO a entidad (recipeService.toEntity), guárdala (recipeService.saveRecipe, ya implementado) y devuelve el resultado convertido de nuevo a DTO (recipeService.toDTO, ya implementado).PUT /api/recipes/{name}(updateRecipe): convierte el DTO a entidad, llama arecipeService.updateRecipe(name, entity)(ya implementado — busca por nombre y reemplaza), y responde404si el resultado esnull(no encontrada) o200con el DTO actualizado si sí se encontró.DELETE /api/recipes/{id}(deleteRecipe): llama arecipeService.deleteRecipe(id)(ya implementado).
- Reutiliza el patrón de
getRecipeById:Optional/valor nulo → decide entreResponseEntity.ok(...)yResponseEntity.notFound().build(). - No necesitas tocar
RecipeService.saveRecipe,updateRecipenideleteRecipe: ya delegan correctamente al repositorio. - Si tienes dudas de qué status code corresponde, revisa la tabla del nivel 0.
./mvnw test -Dgroups=nivel1,nivel2,nivel3Correctores (no los modifiques):
RecipeControllerTest.java
(métodos @Tag("nivel3")) y
RecipeServiceTest.java
(métodos @Tag("nivel3"), prueban toEntity con cada tipo de chef).
Ya tienes un CRUD real y funcionando — no subestimes lo que acabas de lograr, muchas apps "grandes" no hacen mucho más que esto por debajo. Sigue con el nivel 4.