Proyecto compartido. En el taller de Intermodular que abre esta semana has trabajado enlaces rotos y formato. En Servidor continúas la implementación del mismo producto.
Se explica
25 minutos · explicación y demostración
Llegas con un CRUD en memoria y una colección que comprueba su contrato. El contrato es lo que el cliente puede esperar de cada petición. Hoy revisarás las entidades de tu proyecto con los mismos criterios y corregirás diferencias antes de cambiar su diseño en la UD3.
La diferencia que importa
Tu API funciona. Eso ya no es noticia: funciona desde la UD1.
Lo que se pide hoy es otra cosa, y es la que separa un ejercicio de un entregable:
Que otra persona pueda comprobar que funciona sin que tú estés delante.
Piensa en qué haría un compañero que abriese tu repositorio ahora mismo. ¿Sabría arrancarlo? ¿Sabría qué endpoints hay? ¿Sabría qué debe responder cada uno? ¿Podría comprobarlo sin escribir una sola petición a mano?
Si la respuesta a las cuatro no es sí, el trabajo no está terminado aunque el código sea correcto.
Verificar un contrato sin mirar la implementación
Un contrato describe qué puede pedir el cliente y qué resultado debe observar. Incluye métodos, rutas, campos y estados; también los casos de error. Puede cumplirse con una lista en memoria o con una base de datos. Precisamente por eso vamos a fijarlo antes de sustituir el almacenamiento.
La comprobación comienza con datos que prepara la propia colección. Crear un recurso y guardar el identificador de su respuesta evita depender de que alguien haya dejado previamente el registro 1. Al final se limpian los datos creados o se utiliza un conjunto de prueba identificado. Una segunda ejecución debe producir resultados equivalentes.
Si falla una petición, se distingue el contrato de su implementación: una ruta mal escrita es un problema de la prueba; una ruta acordada que devuelve una respuesta incorrecta es un defecto del servidor. Se conserva la petición que demuestra el problema y se corrige la pieza correspondiente. Revisar esta versión significa poder explicar ambos lados de esa comparación.
Se trabaja
140 minutos · implementación guiada sobre el proyecto propio
Paso 1 · Retomar el proyecto y preparar la comprobación
- Abre la colección de la sesión 7 y ejecútala contra tu aplicación recién arrancada. Guarda qué comprobaciones pasan y cuáles fallan.
- Abre el README y los controladores de todas tus entidades. Contrasta las rutas documentadas con las que existen en el código.
- Prepara una tabla con requisito, petición que lo comprueba y resultado. Usa el dominio que elegiste, no una nueva aplicación de ejemplo.
Paso 2 · Revisar la versión en memoria: ejemplo de criterios de aceptación
Trabaja sobre las entidades existentes. Primero comprueba el modelo contra la tabla y añade únicamente los campos que falten. Si falta proyectoId en Tarea, declara el atributo y sus accesos, permite enviarlo al crear y devuelve su valor al consultar; de momento es una referencia numérica, no una relación JPA. Después recorre la tabla de operaciones, asociando cada fila a un método y a una petición guardada. Corrige una fila y repítela antes de seguir.
Modelo
| Clase | Campos mínimos |
|---|---|
Proyecto |
id, nombre, descripcion, activo |
Tarea |
id, titulo, prioridad, completada, proyectoId |
Los identificadores los asigna el servidor y no se repiten aunque se borren elementos.
Endpoints exigidos
| Método y ruta | Caso | Respuesta |
|---|---|---|
GET /proyectos |
Siempre | 200 con el array |
GET /proyectos?activo=true |
Filtro opcional | 200 con los que coincidan |
GET /proyectos/{id} |
Existe / no existe | 200 / 404 |
POST /proyectos |
Correcto | 201, cuerpo y Location |
PUT /proyectos/{id} |
Existe / no existe | 200 / 404 |
PATCH /proyectos/{id} |
Existe / no existe | 200 / 404 |
DELETE /proyectos/{id} |
— | 204 |
GET /tareas |
Siempre | 200 con el array |
GET /tareas?completada=true |
Filtro opcional | 200 con las que coincidan |
GET /tareas/{id} |
Existe / no existe | 200 / 404 |
POST /tareas |
Correcto | 201, cuerpo y Location |
PUT /tareas/{id} |
Existe / no existe | 200 / 404 |
PATCH /tareas/{id} |
Existe / no existe | 200 / 404 |
DELETE /tareas/{id} |
— | 204 |
GET /proyectos/{id}/tareas |
Proyecto existe | 200 con sus tareas |
GET /proyectos/{id}/tareas |
Proyecto no existe | 404 |
Las dos últimas filas son las únicas que no has hecho nunca. Piensa antes de escribir: ¿en qué controlador vive esa ruta? ¿Qué distingue «este proyecto no tiene tareas» de «este proyecto no existe», y qué debe responder cada caso?
Reglas que se comprueban
- Ninguna ruta contiene un verbo. La acción la expresa el método HTTP.
- Ninguna operación de escritura acepta el
iddel cuerpo: manda la ruta. PUTsustituye por completo;PATCHsolo toca lo que recibe.- Una colección sin resultados devuelve
200con[], nunca404. - El filtro es opcional; sin él salen todos los elementos.
Estoy atascado · la ruta anidada
Fíjate en qué identifica y qué filtra. El {id} del proyecto identifica, así que va en la ruta; eso ya lo decidiste en la UD1.
Para saber qué tareas son suyas necesitas recorrer la lista de tareas comparando su proyectoId. Antes de eso debe comprobarse que el proyecto existe: si no existe, la respuesta no es una lista vacía.
Paso 3 · La prueba de aceptación
Prepara un escenario que cree sus propios datos: alta de proyecto → guardar id del proyecto → alta de tarea con ese id → consultas y modificaciones → borrar tarea → borrar proyecto. Guarda los ids en variables distintas. Ejecuta la secuencia dos veces sin reiniciar para detectar si depende de datos residuales; después reinicia y ejecútala otra vez para comprobar que sabe prepararse desde memoria vacía.
El quinto criterio es el que separa una colección de una lista de peticiones. Si la segunda ejecución falla, es que el escenario deja datos, o que da por hecho un estado inicial que ya no se cumple.
Paso 4 · Preparar la evidencia de esta versión
En tu repositorio del módulo:
- El proyecto completo, arrancable con
mvnw spring-boot:run. - La colección exportada, en una carpeta
pruebas/. - Un
README.mdque quepa en una pantalla y responda a tres cosas: cómo se arranca, qué endpoints hay y cómo se ejecuta la colección. - Un las decisiones técnicas con estas cuatro, cada una en dos o tres frases:
- Qué responde tu
DELETEsobre algo inexistente, y por qué elegiste eso. - Qué hace tu API si el
iddel cuerpo no coincide con el de la ruta. - Qué devuelve
GET /proyectos/{id}/tareascuando el proyecto existe y no tiene tareas, y por qué no es un404. - Si dejaste Jackson tolerante o estricto con las claves desconocidas, y qué pierdes con tu elección.
- Qué responde tu
El README no es burocracia
Es la parte del entregable que se lee primero y la que decide si alguien puede usar tu trabajo. Un backend excelente con un README que no explica cómo arrancarlo es, para quien llega nuevo, un backend que no funciona.
Paso 5 · Comprobar el resultado
Pásate esta lista tú mismo. Es la misma con la que se corrige.
| Comprobación | Cómo lo verificas |
|---|---|
| Arranca desde cero | Clona tu propio repositorio en otra carpeta y arráncalo |
| Los endpoints están completos | La colección cubre las dieciséis filas |
| Los códigos son correctos | La colección está en verde |
| Es repetible | La ejecutas dos veces seguidas |
| Se entiende sin ti | Se lo das a un compañero y no te pregunta nada |
| Las decisiones están escritas | las decisiones técnicas responde a las cuatro |
La quinta es la de verdad. Dáselo a alguien y no le expliques nada. Cada pregunta que te haga es una línea que le falta a tu README.
Paso 6 · Lo que esta versión todavía hace mal
Compruébalo y anótalo, porque es el índice de la UD3:
| Prueba esto | Lo que pasa | Lo correcto | Dónde se arregla |
|---|---|---|---|
POST /tareas con {} |
Crea una tarea sin nada | 400 diciendo qué falta |
UD3 |
POST con prioridad "urgentísima" |
La acepta | 400: no es un valor válido |
UD3 |
POST /tareas con un proyectoId inexistente |
La acepta | 400 o 404, pero no un 201 |
UD3 |
Cualquier 400 |
Cuerpo genérico e inútil | Un mensaje que diga qué corregir | UD3 |
| Añadir un campo interno al modelo | Se publica solo | Se publica lo que tú decidas | UD3, con DTO |
| Reiniciar | Se pierde todo | Sigue ahí | UD5 |
Fíjate en la tercera fila: tu API acepta tareas que pertenecen a proyectos que no existen. Nada en el código lo impide, porque nadie ha escrito todavía qué es una tarea válida.
Ver respuestas
1 · Que otra persona pueda arrancarlo y comprobar que funciona sin que tú estés delante: código, pruebas ejecutables y documentación mínima.
2 · Porque deja el servidor en un estado distinto del que suponía, así que a partir de la segunda vez sus comprobaciones dejan de significar nada.
3 · Un 200 con un array vacío. El recurso existe; lo que no hay son elementos, y eso no es un error.
4 · Porque no hay validación: nadie ha escrito todavía qué condiciones debe cumplir una tarea para ser válida, así que Jackson construye el objeto y el controlador lo guarda.
Paso 7 · Comprobar y registrar el resultado del proyecto
- Reproduce el ciclo CRUD de la entidad principal y de las relacionadas previstas hasta ahora. Cada operación debe coincidir con su contrato documentado.
- Reinicia, recrea los datos mediante la colección y ejecútala de nuevo. Deja registrado que perder datos al reiniciar sigue siendo una limitación conocida de esta versión.
Cierre
15 minutos · resultado comprobable y explicación individual
Al terminar la sesión:
Otra persona reproduce las operaciones principales y un fallo previsto usando únicamente el repositorio y sus instrucciones.
Cada integrante explica una decisión del código apoyándose en una de las comprobaciones realizadas.