====== 10 - La Forja en Spring Boot ====== El contrato diseñado a mano en el paso 09 se implementa: La Forja pasa de consola a **API REST** con **Spring Boot**. Las capas del paso 08 se quedan (negocio, persistencia, modelo); lo que cambia es la capa de presentación, que en vez de menú de consola atiende **HTTP**. ===== 1. Qué se pide ===== * El proyecto **Spring Boot** con la dependencia web (desde **Spring Initializr**), con tu paquete base y las capas 08 trasladadas. * Los **controladores** que implementan la tabla del paso 09 fila a fila: cada endpoint con su método, su ruta y el código de estado prometido — sin inventar nuevas rutas ni respuestas: si el contrato se había de cambiar, se discute y se cambia en el contrato primero. * Las excepciones de negocio del paso 05 ya no se capturan a mano: vuelan hasta una clase única de **manejo global** que las traduce a los estados HTTP de la tabla de fallos de 09 — y cada traducción lleva el cuerpo de error previsto. * Los ''IO.println'' de los sucesos relevantes pasan a **logs** (fachada **SLF4J**), con niveles elegidos y sin datos sensibles en los mensajes. * Todas las filas del contrato se comprueban con **curl** como abajo. ===== 2. Con qué ===== * Todo lo del tema: el **DispatcherServlet** como front controller, controladores anotados (''@RestController'', ''@GetMapping''...), **''ResponseEntity''** para el cuerpo y el estado de cada respuesta, el **contenedor de IoC** (que ocupa el lugar del ensamblado manual del 08) y el **manejo global de excepciones** (''@RestControllerAdvice''). * El reparto de anotaciones es el del tema: el controlador en la presentación, el servicio en el negocio, el repositorio en la persistencia — cada una con la anotación de estereotipo que toque. ===== 3. Decisiones tuyas ===== * ¿Cómo lee el controlador lo que le llega del cliente (rutas identificadas, cuerpo del POST, parámetro del filtro)? Cada fila del contrato se traduce a una firma de método. * ¿En qué filas del contrato devuelves cuerpo y en cuáles no? El estado y el cuerpo son dos decisiones separadas. * ¿Cómo decide el manejador global qué estado le toca a cada excepción? Y ¿el error no previsto qué estado promete y qué revela al cliente? * ¿Qué entra en el log de cada suceso importante y con qué nivel? ¿Y qué relación hay entre los niveles de los fallos ''4xx'' y ''5xx''? * ¿Dónde vive el registro de cada suceso (acceso, error, arranque)? Decide el punto y defiende el criterio. ===== 4. Comprobación ===== **Con ''curl''**, cada fila del contrato, probada en orden: * El listado de héroes y las fichas se devuelven con los códigos prometidos, y en un JSON que se lee. * Se registra un héroe: el código de promesa llega y, si llevaba cuerpo, el héroe creado con su id del negocio. * Una ficha inexistente devuelve el código de la tabla de fallos y su cuerpo de error, sin mensaje de máquina. * Registrar con datos imposibles (nivel negativo, campo faltante) devuelve el código del contrato y el cuerpo de error construido desde la excepción. * Un error no previsto (el que produce el manejo global por si acaso) devuelve ''500'': el detalle queda en el **log**, no en la respuesta. * En los logs: cada registro relevante aparece con su nivel y ninguno incluye datos sensibles. * El programa compila sin capas cruzadas: la causa raíz de cada fallo queda dónde toca. ===== 5. Pendientes ===== * El estado del repositorio en memoria es único, y ahora cada petición a la vez vive en su hilo -> concurrencia (**11**). * Cualquiera puede borrar héroes: falta saber **quién** consulta y **qué** puede hacer -> **tokens** (**12**).