ISIS2211 · Release 2 · Angular + Spring Boot
http.post()
Ya sabe usar httpResource para traer datos con un GET reactivo.
Ahora el usuario quiere crear un artista nuevo. Para eso existe
HttpClient y el patrón Observable + subscribe.
Hay dos herramientas, con roles distintos. Usarlas al revés es el error más frecuente del release.
Hace el GET automáticamente al inyectar el servicio.
Le entrega value(), isLoading()
y error() listos para la plantilla.
No hay subscribe.
Construye la petición pero no la envía.
Solo se dispara cuando el componente llama .subscribe()
— por ejemplo, al hacer submit de un formulario.
En ArtistaService ambas conviven:
// ── GET reactivo: httpResource lo maneja todo ──────────────────────── artistasResource = httpResource<Artista[]>( () => environment.ARTISTAS_URL ); // ── POST puntual: HttpClient + Observable + subscribe ──────────────── crear(nuevoArtista: NuevoArtista): Observable<Artista> { return this.http.post<Artista>(environment.ARTISTAS_URL, nuevoArtista); }
"¿Por qué crear() usa HttpClient
y no httpResource?"
La respuesta: httpResource es para lecturas reactivas que se
disparan solas. Un POST ocurre cuando el usuario decide crearlo — es un
evento puntual, no un estado continuo.
Esta es la idea central. Cuando el servicio hace
this.http.post(url, datos),
no ocurre ninguna petición HTTP. Solo se crea la descripción
de lo que pasará. El Observable es "frío": necesita que alguien llame
.subscribe() para encenderse.
http.post() es armar el carrito en la app.
.subscribe() es confirmar el pedido. Hasta que no confirmas, la cocina no sabe que existes.
// El GET viaja al crear el servicio artistasResource = httpResource<Artista[]>( () => environment.ARTISTAS_URL ); // En la plantilla: @if (artistasResource.isLoading()) { Cargando… } @for (a of artistasResource.value()) { … }
// Solo construye. No envía nada. crear(nuevo: NuevoArtista): Observable<Artista> { return this.http .post<Artista>(url, nuevo); } // En el componente, al submit: this.svc.crear(datos).subscribe({ next: (a: Artista) => { /* éxito, a.id ya viene asignado */ }, error: (e: HttpErrorResponse) => { /* error */ } });
Rellene el formulario y presione Crear artista. El simulador muestra paso a paso qué ejecuta Angular — igual que su componente lo haría. Use el botón Simular error para ver qué pasa cuando el servidor falla.
crear(datos)Así quedan el servicio y el componente de formulario. Nótese la separación de roles: el servicio habla con la red, el componente solo orquesta.
@Injectable({ providedIn: 'root' }) export class ArtistaService { private readonly http: HttpClient = inject(HttpClient); // GET reactivo — signals gratis readonly artistasResource = httpResource<Artista[]>( () => environment.ARTISTAS_URL ); // POST puntual — Observable frío, se dispara con subscribe crear(nuevo: NuevoArtista): Observable<Artista> { return this.http.post<Artista>( environment.ARTISTAS_URL, nuevo ); } }
@Component({ /* … */ }) export class ArtistaFormComponent { private readonly svc: ArtistaService = inject(ArtistaService); onSubmit(formData: NuevoArtista): void { this.svc.crear(formData) // ① llama el servicio .subscribe({ // ② subscribe enciende el Observable next: (artista: Artista) => { // ③a éxito: artista es el Artista completo que retornó el servidor, // ya con su id asignado — por eso se puede leer artista.id. console.log('Artista creado con id:', artista.id); this.svc.artistasResource.reload(); // refresca la lista }, error: (err: HttpErrorResponse) => { // ③b error: algo falló en el servidor console.error('Error al crear:', err); } }); } }
HttpClient directamente. La regla se aplica
también al revés: el servicio nunca accede al formulario.
Si mañana el back cambia de URL o de formato, solo se toca ArtistaService.
El síntoma: el formulario envía, no hay error de consola, pero el artista nunca aparece en
la lista. La causa: http.post() devuelve un Observable
frío que nadie encendió. Solución: agregar .subscribe()
en el componente.
Funciona, pero viola la separación de responsabilidades. El componente termina hablando directo con la red. Si el endpoint cambia, hay que buscar todos los componentes que lo usen. Siempre: el componente llama al servicio, el servicio llama a la red.
El artista se crea en el servidor, pero artistasResource.value()
sigue mostrando los datos de antes. Después del next()
exitoso, llame artistasResource.reload().
En el bloque next:, el argumento recibido es el artista
tal como lo guardó el servidor (generalmente con un
id nuevo asignado). Si llega vacío o sin
id, revise que el back retorne el objeto completo
— es un contrato entre front y back.
Tres preguntas del tipo que aparecen en la del release.
1. El estudiante escribe this.svc.crear(datos)
en onSubmit() pero no agrega
.subscribe(). ¿Qué ocurre?
subscribe() no hay
petición. El bug es silencioso — no hay error de consola. Por eso es uno de los más
difíciles de detectar.
2. Después de un POST exitoso, la lista de artistas sigue sin mostrar el nuevo artista.
El next() se ejecutó sin error. ¿Qué falta?
httpResource no sabe que el POST ocurrió.
.reload() le dice "vuelve a buscar" y actualiza
value() en todos los componentes que usen el servicio.
3. Un compañero propone inyectar HttpClient
directamente en el componente de formulario para simplificar. ¿Qué problema trae eso?