Proyecto compartido. En el taller de Intermodular que abre esta semana has trabajado issues, tablero y la primera pull request. En Servidor continúas la implementación del mismo producto.
Se explica
25 minutos · explicación y demostración
Ya puedes añadir, listar y consultar objetos por su identificador en memoria. Hoy conservarás esas operaciones, incorporarás la sustitución y el borrado y añadirás un filtro al listado. El identificador permitirá distinguir registros y pasará a asignarlo el servidor. PUT sustituye los datos de un recurso; DELETE solicita su eliminación.
Dónde estamos
Esto es lo que responde tu API al terminar la sesión 3:
| Método y ruta | Estado |
|---|---|
GET /tareas |
Funciona |
GET /tareas/{id} |
Funciona, con un defecto conocido |
POST /tareas |
Funciona, con un defecto conocido |
PUT /tareas/{id} |
No existe |
DELETE /tareas/{id} |
No existe |
Hoy se cierra la tabla.
Qué significa que el CRUD esté completo
Las operaciones comparten el mismo estado. Si creas un registro, tiene que aparecer en el listado y poder consultarse por su identificador; si lo modificas, las lecturas siguientes deben reflejar el cambio; si lo borras, tiene que desaparecer tanto del listado como del detalle. Cinco métodos que funcionan aislados no bastan si cada uno utiliza una colección diferente.
En este proyecto, el servidor asignará el identificador. El cliente enviará los datos que desea crear y recibirá el identificador asignado; así evitamos que distintos clientes elijan el mismo número. En una modificación, el identificador de la ruta selecciona el registro existente. Primero se busca y después se cambia: que no exista es un caso que la aplicación debe tratar.
Hoy la colección vive en el proceso Java. El reinicio elimina sus datos y es una limitación conocida de esta versión. No se corrige guardando el JSON en el navegador: la persistencia del servidor se incorporará con PostgreSQL. La prueba de hoy recorre crear, consultar, modificar, volver a consultar, borrar y comprobar la ausencia, en ese orden, sin editar el código entre peticiones.
Se trabaja
140 minutos · implementación guiada sobre el proyecto propio
Paso 1 · Retomar el proyecto y preparar la comprobación
Continúa con el flujo del backend. Comprueba que la PR de la sesión 3 está revisada e integrada. Crea una issue para completar el CRUD en memoria, indicando las operaciones que comprobarás. En los comandos se usa el número 13: sustitúyelo por el número real de tu nueva issue.
En la carpeta del backend, con git status sin cambios pendientes:
git switch main
git pull --ff-only
git switch -c 13-crud-en-memoria
Realiza los cambios de hoy en esa rama. No vuelvas a enviar código directamente a main: se integra mediante una PR, como has practicado en Intermodular.
- Abre el controlador y la clase del modelo utilizados en la sesión 3. Arranca y reproduce el alta y el listado con tu cliente HTTP.
- Localiza la lista que guarda los objetos y el método POST. Ahí revisarás la asignación de identificadores; conserva las rutas que ya funcionan.
- Prepara dos objetos con datos diferentes. Guarda las peticiones de alta para recrearlos después de cada reinicio, ya que todavía no hay base de datos.
Paso 2 · El primer defecto · el id lo pone el cliente
Antes de modificar el POST, reinicia para partir de la lista vacía de la sesión 3. Reproduce primero el fallo de los identificadores elegidos por el cliente con estas peticiones:
POST /tareascon"id": 1y el título que quieras.POST /tareasotra vez, también con"id": 1y otro título.GET /tareas/1.
Consulta también GET /tareas: hay dos tareas distintas con el mismo identificador, pero GET /tareas/1 solo encuentra la primera de la lista. La segunda aparece en el listado, aunque no puedes seleccionarla de forma inequívoca por su id.
Quién decide el identificador
En nuestra API, el servidor asigna el identificador. El cliente envía el contenido de la tarea y el servidor lleva un contador para evitar identificadores repetidos en las pruebas secuenciales de esta versión. Esta es una decisión de diseño del proyecto, no una obligación universal de HTTP.
Nuestro POST devuelve la tarea creada con su id. Lee ese valor en la respuesta para construir las siguientes consultas y modificaciones. Más adelante conocerás también la cabecera Location, que permite indicar la dirección del recurso creado.
Ahora corrige el POST. En TareaController, conserva la lista existente, añade a su lado private int siguienteId = 1; y sustituye únicamente el método crear por esta versión:
private final List<Tarea> tareas = new ArrayList<>();
private int siguienteId = 1;
@PostMapping
public Tarea crear(@RequestBody Tarea tarea) {
tarea.setId(siguienteId);
siguienteId = siguienteId + 1;
tareas.add(tarea);
return tarea;
}
La declaración de tareas aparece para situar el nuevo contador: no dupliques el atributo que ya existe. Cada alta asigna el valor actual, aumenta el contador y añade la tarea a la lista. En esta versión, el contador y la lista se reinician al arrancar la aplicación.
Guarda y reinicia para eliminar los registros duplicados. En Postman prepara POST http://localhost:8080/tareas, selecciona Body → raw → JSON y envía:
{
"titulo": "Revisar el login",
"prioridad": "alta",
"completada": false
}
La respuesta debe contener esos campos y "id": 1. Cambia el título por Actualizar dependencias, la prioridad por baja y envía de nuevo: debe recibir "id": 2. Consulta el listado para ver ambas tareas. Como tercera prueba, añade "id": 999 al cuerpo, separado del resto de campos por una coma: el servidor debe devolver "id": 3. La prueba de borrar y crear llegará después de implementar DELETE.
Paso 3 · PUT · sustituir una tarea entera
Añade el método siguiente dentro de TareaController, antes de su última llave. Conserva los GET y el POST anteriores. Añade import org.springframework.web.bind.annotation.PutMapping; junto a los demás imports; RequestBody y PathVariable ya se utilizan en el controlador.
@PutMapping("/{id}")
public Tarea actualizar(
@PathVariable(name = "id") int id,
@RequestBody Tarea datos) {
for (int i = 0; i < tareas.size(); i++) {
if (tareas.get(i).getId() == id) {
datos.setId(id);
tareas.set(i, datos);
return datos;
}
}
return null;
}
- Por qué el id va en la ruta y no en el cuerpo
- Porque identifica qué tarea se sustituye. Es la regla de la sesión 2: sin ese dato la petición no significa nada. Lo que va en el cuerpo es el contenido nuevo.
- Por qué
datos.setId(id) - Para que mande la ruta. Si el cuerpo trae un id distinto —o ninguno— y no lo forzamos, la tarea se guardaría con un identificador equivocado y desaparecería de las consultas. Cuando dos sitios dicen lo mismo, hay que decidir cuál gana y dejarlo escrito.
- Qué diferencia hay entre
ieid ies la posición dentro de la lista y empieza en 0;ididentifica la tarea y procede de la URL. Una lista con tareas de ids 2 y 3 tiene posiciones 0 y 1.tareas.get(i)obtiene el objeto de esa posición ygetId()permite comprobar si es el que buscamos.- Qué cambia
tareas.set(i, datos) - Sustituye el objeto de la posición
ipor el objeto recibido. No añade otra tarea ni cambia el tamaño de la lista.datos.setId(id), en cambio, modifica un campo de ese objeto antes de guardarlo. Son dos operaciones distintas. - Qué ocurre con un campo omitido
- Este PUT sustituye todos los datos editables. En nuestro modelo, una prioridad omitida queda en
nully unacompletadaomitida queda enfalse; no se recuperan los valores anteriores. Aún falta validar los campos obligatorios, algo que se abordará en la UD3. PATCH permite modificaciones parciales y se introducirá en la UD2. - Qué pasa si el id no existe
- Devuelve
null, y por tanto un200con el cuerpo vacío. Es el mismo defecto que ya anotaste enGET /tareas/{id}. Sigue anotado.
Primera modificación completa desde Postman
- Guarda el controlador, reinicia y espera a que arranque. El reinicio ha vaciado la lista: envía primero el POST sin id del paso 2. Debe crear la tarea 1. Un PUT a una lista vacía no puede modificarla.
- Abre otra pestaña HTTP en Postman. Selecciona PUT y escribe
http://localhost:8080/tareas/1. Si estás utilizando otro registro, sustituye1por el id real de su respuesta POST; no escribas literalmente{id}. - Selecciona Body → raw → JSON y escribe todos los campos editables:
{
"titulo": "Revisar el login y cerrar la incidencia",
"prioridad": "baja",
"completada": true
}
- Pulsa Send. Debes recibir
200 OKy este objeto:
{
"id": 1,
"titulo": "Revisar el login y cerrar la incidencia",
"prioridad": "baja",
"completada": true
}
- En la pestaña de consultas, envía GET a
http://localhost:8080/tareas/1, con Body → none. Debe devolver los datos modificados. Consulta despuéshttp://localhost:8080/tareas: debe seguir habiendo una sola tarea con el mismo id.
Comprueba ahora una omisión deliberada: en el cuerpo del PUT elimina la línea de prioridad, manteniendo una coma entre titulo y completada. Envía el PUT y consulta el detalle: la prioridad debe ser null, porque has sustituido el objeto por otro que no la incluye. Restaura el JSON completo anterior y vuelve a enviarlo antes de continuar. Cambiar el texto en Postman sin pulsar Send no modifica los datos del servidor.
Paso 4 · Completar consulta individual, listado y borrado
Conserva el GET de detalle de la sesión 3 y el POST y PUT que acabas de comprobar. Sustituye el GET de listado por el siguiente e importa RequestParam. El parámetro Boolean puede valer null, lo que permite distinguir «sin filtro» de false:
@GetMapping
public List<Tarea> lista(
@RequestParam(name = "completada", required = false) Boolean completada) {
if (completada == null) {
return tareas;
}
List<Tarea> resultado = new ArrayList<>();
for (Tarea tarea : tareas) {
if (tarea.isCompletada() == completada) {
resultado.add(tarea);
}
}
return resultado;
}
La lista local resultado recoge las coincidencias para esta respuesta. Añadir una tarea a resultado no la elimina de tareas: al quitar el filtro volverás a ver todos los registros. Sustituye el método de listado anterior; no dejes dos métodos con @GetMapping sin ruta.
Añade DELETE dentro del mismo controlador e importa org.springframework.web.bind.annotation.DeleteMapping:
@DeleteMapping("/{id}")
public void eliminar(@PathVariable(name = "id") int id) {
tareas.removeIf(tarea -> tarea.getId() == id);
}
removeIf recorre la lista y elimina los elementos para los que la condición resulta verdadera. La expresión tarea -> tarea.getId() == id es una lambda: a la izquierda de -> se da un nombre al elemento que se está examinando; a la derecha se indica la comprobación. Se lee «para cada tarea, comprueba si su identificador coincide con el de la ruta». No usa la posición de la lista.
Guarda y reinicia una vez. Prepara los datos y comprueba el filtro y el borrado sin editar código entre peticiones:
- Envía dos POST sin id: uno con
completada: falsey otro concompletada: true, utilizando títulos distintos. Deben recibir ids 1 y 2. - Consulta GET
http://localhost:8080/tareas: deben aparecer ambas. Consultahttp://localhost:8080/tareas?completada=true: solo debe aparecer la segunda. Cambiatrueporfalse: solo debe aparecer la primera. Quita?completada=false: deben volver a aparecer ambas. - Abre otra pestaña HTTP, selecciona DELETE, escribe
http://localhost:8080/tareas/1y deja Body → none. El id de la URL basta para seleccionar la tarea; no se necesita JSON. Pulsa Send. - Debes recibir
200 OKcon el cuerpo vacío: el método Java devuelvevoid. En la UD2 ajustarás el estado a204 No Content. El cuerpo vacío por sí solo no demuestra que se haya borrado el registro. - Envía GET
http://localhost:8080/tareas: solo debe quedar la tarea 2. GEThttp://localhost:8080/tareas/1devuelve200y cuerpo vacío, la limitación conocida de la consulta de un id inexistente. GEThttp://localhost:8080/tareas/2debe seguir devolviendo la segunda tarea.
| Método y ruta | Recibe | Devuelve |
|---|---|---|
GET /tareas |
Nada | El array de todas las tareas |
GET /tareas?completada=true |
Filtro opcional | Solo las que coincidan |
GET /tareas/{id} |
El id en la ruta | Esa tarea como objeto |
POST /tareas |
La tarea en el cuerpo | La tarea creada, con su id asignado |
PUT /tareas/{id} |
El id en la ruta y la tarea en el cuerpo | La tarea sustituida |
DELETE /tareas/{id} |
El id en la ruta | Nada |
Requisitos que se comprueban:
- El identificador lo asigna el servidor y no se repite durante esta ejecución, ni después de borrar una tarea. Tras reiniciar, la lista y el contador comienzan de nuevo.
- El filtro
completadaes opcional. Sin él, salen todas. DELETEno devuelve cuerpo. Declara el método comovoidy comprueba en Postman qué código de estado sale.- Todas las rutas cuelgan de un único
@RequestMappinga nivel de clase. - No se escribe ninguna ruta con un verbo dentro, del tipo
/tareas/borrar/3. La acción la expresa el método HTTP.
Estoy atascado · el filtro opcional
Ya lo has hecho en la sesión 2, pero con un String. Aquí el parámetro es un Boolean con required = false: si no llega, vale null, y entonces devuelves la lista entera.
Usa el envoltorio Boolean y no el tipo primitivo boolean. Un boolean no puede valer null, así que no podrías distinguir «no me han filtrado» de «me han pedido las no completadas».
Estoy atascado · el borrado
removeIf modifica la lista y devuelve un booleano que indica si ha eliminado algún elemento. En este método no utilizamos ese resultado: void significa que eliminar() no devuelve un objeto para el cuerpo HTTP.
Si no desaparece la tarea, compara el id de la URL con el que figura en el listado. No deduzcas el identificador a partir de su posición: la primera tarea de la lista puede tener id 2 después de borrar la de id 1.
Paso 5 · La prueba de aceptación
Una API no está terminada porque compile. Está terminada cuando una secuencia de peticiones se comporta como se esperaba.
Para este escenario concreto, reinicia una vez y comprueba que el listado está vacío. Ejecuta las diez peticiones sin reiniciar entre ellas. Así los ids 1 y 2 corresponden a las altas indicadas. Anota estado y cuerpo y predice cada resultado antes de enviar. En los dos primeros POST utiliza el JSON completo del paso 2, con los títulos y prioridades de la tabla y completada: false, sin id. En el PUT conserva el título y la prioridad de la tarea 2 y cambia solo el valor de completada a true, enviando también los demás campos.
| # | Petición | Qué debe ocurrir |
|---|---|---|
| 1 | GET /tareas |
[] |
| 2 | POST /tareas · «Revisar el login», alta |
Devuelve la tarea con id 1 |
| 3 | POST /tareas · «Actualizar dependencias», baja |
Devuelve la tarea con id 2 |
| 4 | GET /tareas |
Array con las dos |
| 5 | GET /tareas/2 |
Solo la segunda, como objeto |
| 6 | PUT /tareas/2 · misma tarea con completada: true |
La devuelve modificada |
| 7 | GET /tareas?completada=true |
Solo la tarea 2 |
| 8 | DELETE /tareas/1 |
Sin cuerpo |
| 9 | GET /tareas |
Solo queda la tarea 2 |
| 10 | POST /tareas · una tercera |
Recibe id 3: no reutiliza el 1 borrado ni el 2 que sigue existiendo |
Después del paso 10, consulta el listado: debe contener dos registros con ids distintos, 2 y 3. Si calculas el nuevo id con tareas.size() + 1, obtendrás 2 y duplicarás el registro existente. La prueba debe detectar también ese caso, no solo que se reutilice el 1.
Guarda estas diez peticiones
No las borres al terminar. En la UD2 aprenderás a agruparlas en una colección, ponerles nombre, sacar la dirección del servidor a una variable y ejecutarlas todas de una vez. Esta lista de diez pasos es el primer borrador de esa colección, y es también la primera versión de lo que en la UD7 serán tests automatizados de Java.
Paso 6 · Completar la segunda entidad del mismo proyecto
Retoma Proyecto.java y ProyectoController.java de la sesión 3. Ya deben permitir crear, listar y consultar proyectos por id en memoria. Aplica ahora las mismas operaciones sobre esa entidad, manteniendo el CRUD de tareas. Si tu dominio utiliza otros nombres, conserva los que ya has elegido.
- En
ProyectoController, localiza la lista de proyectos y añade a su lado su propioprivate int siguienteId = 1;. Modifica su POST para asignar el id, incrementar el contador y añadir el proyecto. Cada controlador mantiene su propia lista y contador; una tarea y un proyecto pueden tener ambos id 1 porque sus rutas son diferentes. - Añade un PUT con
@PutMapping("/{id}"), un id de ruta y@RequestBody Proyecto datos. Adapta el bucle del paso 3 para recorrerproyectos: busca el id, asigna ese id adatos, sustituye el objeto conproyectos.set(i, datos)y devuélvelo. Si no existe, conserva por ahora elreturn null. - Sustituye el GET de listado por un filtro opcional adecuado al modelo. Para
Proyecto, utiliza@RequestParam(name = "activo", required = false) Boolean activo. Sin filtro devuelveproyectos; con filtro recorre la lista y añade aresultadolos proyectos cuyoproyecto.isActivo() == activo. El resultado debe ser unaList<Proyecto>. Si conservabas el filtro demostrativoestadode la sesión 2, sustitúyelo poractivo, que corresponde a un campo real de este modelo. - Añade DELETE con el id de ruta y
proyectos.removeIf(proyecto -> proyecto.getId() == id);. Conserva el GET de detalle que busca el proyecto en la lista. Revisa los imports de las anotaciones que acabas de añadir y los tipos: en este controlador no debe quedar ningúnTareani una referencia a la listatareas. - Guarda y reinicia. En Postman crea un proyecto con POST
http://localhost:8080/proyectosy Body → raw → JSON:
{
"nombre": "Gestor de tareas",
"descripcion": "Organizar las tareas del equipo",
"activo": true,
"numeroDeIncidencias": 0
}
Debe recibir id 1. Crea otro con nombre Archivo de proyectos, descripción Consultar proyectos terminados, activo: false y numeroDeIncidencias: 0; debe recibir id 2. Comprueba, en este orden:
| Petición | Resultado esperado |
|---|---|
GET http://localhost:8080/proyectos |
Los dos proyectos |
GET http://localhost:8080/proyectos/1 |
Solo el primero |
GET http://localhost:8080/proyectos?activo=true |
Solo el primero |
GET http://localhost:8080/proyectos?activo=false |
Solo el segundo |
Envía PUT a http://localhost:8080/proyectos/1, con Body → raw → JSON y este cuerpo completo:
{
"nombre": "Gestor de tareas revisado",
"descripcion": "Organizar y revisar las tareas del equipo",
"activo": false,
"numeroDeIncidencias": 1
}
Consulta el detalle: debe conservar id 1 y mostrar los cuatro valores nuevos. El listado con activo=true debe devolver []; al quitar el filtro vuelven a aparecer ambos proyectos. Envía DELETE a http://localhost:8080/proyectos/1, con Body → none, y comprueba que el listado solo contiene el segundo. Crea un tercer proyecto: debe recibir id 3. Todos estos envíos responden por ahora con 200; el DELETE tiene el cuerpo vacío.
Por último, envía un POST válido a /tareas y comprueba que sus rutas siguen funcionando. Las dos entidades pertenecen al mismo backend, pero todavía no están relacionadas entre sí: esa relación se incorporará más adelante. Antes de continuar debes poder crear, consultar, sustituir, filtrar y borrar en ambas.
Paso 7 · Lo que tu API todavía hace mal
Este apartado no constituye un ejercicio de autocrítica, sino el índice de las cuatro unidades siguientes. Comprueba tú mismo cada punto y anota qué responde.
| Prueba esto | Lo que pasa | Lo correcto | Dónde se arregla |
|---|---|---|---|
GET /tareas/999 |
200 con cuerpo vacío |
404 Not Found |
UD2 |
POST con {} |
Crea una tarea sin título | 400 explicando qué falta |
UD3 |
POST correcto |
Responde 200 |
201 Created |
UD2 |
POST con "completada": "quizás" |
400 sin explicación útil |
Un error legible | UD3 |
| Reiniciar la aplicación | Se pierde todo | Los datos siguen ahí | UD5 |
| Un campo interno del modelo | Se publica sin querer | Solo se publica lo que decidas | UD3, con DTO |
Que sepas enumerar estos seis defectos vale tanto como haber hecho funcionar la API. Saber qué le falta a lo que has construido es la parte difícil de este oficio.
Paso 8 · Revisar y explicar esta versión
Comprueba que tu repositorio contiene el proyecto completo y que puedes explicar el resultado del trabajo:
- El proyecto completo, arrancable con
mvnw spring-boot:run. - El resultado real de las diez peticiones y las diferencias que hayas corregido.
- Una explicación breve de estas tres cuestiones:
- Decisiones. Por qué el id lo pone el servidor y por qué el filtro va en la query string.
- Defectos conocidos. Los seis de la tabla anterior, con tus palabras.
- Una pregunta. Algo que hayas hecho funcionar sin acabar de entender del todo por qué.
Conserva la pregunta pendiente para contrastarla con las explicaciones de la siguiente unidad.
Ver respuestas
1 · En este proyecto centralizamos la asignación para evitar que distintos clientes elijan el mismo número. El contador permite comprobarlo con peticiones secuenciales; esta versión en memoria todavía no resuelve el acceso concurrente.
2 · Nuestro PUT sustituye el objeto almacenado por el recibido. Los campos omitidos toman los valores iniciales del modelo, en lugar de conservar los anteriores. PATCH permitirá expresar una modificación parcial.
3 · En cuanto borras algo. Si creas dos tareas, borras la primera y creas otra, el tamaño vuelve a ser 1 y repartes un id que ya existe.
4 · Porque utiliza una consulta GET para cambiar datos. Los clientes pueden repetir o precargar consultas suponiendo que no modifican el estado; reserva las escrituras para los métodos HTTP correspondientes.
Paso 9 · Comprobar y registrar el resultado del proyecto
- Ejecuta en orden crear, listar, consultar por id, modificar, consultar de nuevo y borrar. Comprueba los datos después de cada escritura, no solo el estado HTTP.
- Crea dos registros sin elegir sus ids: el servidor debe asignar valores diferentes. Consulta un id ausente y anota la limitación que aún tenga la respuesta; los estados se ajustarán en la UD2.
Referencia · Controlador de tareas al terminar la sesión
Utiliza esta versión para contrastar el resultado de los pasos anteriores si encuentras un error de integración. Es el contenido completo de TareaController.java, no un fragmento para añadir al final del archivo. Mantén el paquete y los nombres de tu proyecto y conserva el modelo Tarea.java de la sesión 3, incluido el constructor vacío con @JsonCreator del paso 9. No sustituye las comprobaciones de Postman ni la adaptación del controlador de la segunda entidad.
package com.ejemplo.gestor.controller;
import com.ejemplo.gestor.model.Tarea;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/tareas")
public class TareaController {
private final List<Tarea> tareas = new ArrayList<>();
private int siguienteId = 1;
@GetMapping
public List<Tarea> lista(
@RequestParam(name = "completada", required = false) Boolean completada) {
if (completada == null) {
return tareas;
}
List<Tarea> resultado = new ArrayList<>();
for (Tarea tarea : tareas) {
if (tarea.isCompletada() == completada) {
resultado.add(tarea);
}
}
return resultado;
}
@GetMapping("/{id}")
public Tarea detalle(@PathVariable(name = "id") int id) {
for (Tarea tarea : tareas) {
if (tarea.getId() == id) {
return tarea;
}
}
return null;
}
@PostMapping
public Tarea crear(@RequestBody Tarea tarea) {
tarea.setId(siguienteId);
siguienteId = siguienteId + 1;
tareas.add(tarea);
return tarea;
}
@PutMapping("/{id}")
public Tarea actualizar(
@PathVariable(name = "id") int id,
@RequestBody Tarea datos) {
for (int i = 0; i < tareas.size(); i++) {
if (tareas.get(i).getId() == id) {
datos.setId(id);
tareas.set(i, datos);
return datos;
}
}
return null;
}
@DeleteMapping("/{id}")
public void eliminar(@PathVariable(name = "id") int id) {
tareas.removeIf(tarea -> tarea.getId() == id);
}
}
Cierre
15 minutos · resultado comprobable y explicación individual
Al terminar la sesión:
El CRUD de ambas entidades funciona mediante las peticiones del cliente HTTP y el README declara que pierde los datos al reiniciar. La colección automatizada se construirá en la sesión 7; hoy deben quedar comprobados los efectos de cada operación.
Cada integrante explica una decisión del código apoyándose en una de las comprobaciones realizadas.
Antes de cerrar, publica la rama y abre su PR. Utiliza el nombre de rama con el número real de la issue creada al inicio.
git status
git add .
git diff --cached
git commit -m "Completar CRUD en memoria"
git push -u origin 13-crud-en-memoria
Antes del commit, revisa que solo preparas los archivos del proyecto y que target/ queda excluido. En la PR hacia main, incluye Closes #13 con el número real y los pasos para comprobar crear, listar, consultar, modificar y borrar. Solicita la revisión sobre la rama, atiende las correcciones y fusiona cuando se hayan comprobado los criterios. Comprueba además que el README integrado declara la pérdida de datos al reiniciar. La revisión se realiza sobre el backend local; su puesta en producción llegará más adelante en Intermodular.