ISIS2211  ·  Release 2  ·  Angular + Spring Boot

Cómo funciona 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.

La regla que no cambia

Hay dos herramientas, con roles distintos. Usarlas al revés es el error más frecuente del release.

httpResource  — para leer (GET)

Hace el GET automáticamente al inyectar el servicio. Le entrega value(), isLoading() y error() listos para la plantilla. No hay subscribe.

HttpClient  — para actuar (POST / PUT / DELETE)

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);
}
Pregunta frecuente

"¿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.

El Observable frío: se construye, no se ejecuta

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(url, datos)
Observable creado
🔵 frío — inactivo
.subscribe()
Petición enviada
🟡 en vuelo
next(artista)
o
error(err)
La analogía con una orden para un domicilio

http.post() es armar el carrito en la app. .subscribe() es confirmar el pedido. Hasta que no confirmas, la cocina no sabe que existes.

Diferencia con httpResource

httpResource  — se suscribe solo
// 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()) {
  …
}
HttpClient.post  — espera subscribe
// 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 */ }
});

Simulador  — vea el Observable en acción

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.

  artista-form.component.ts  +  artista.service.ts
🔵 Observable frío
1
El componente llama crear(datos)
this.artistaService.crear(nuevoArtista)
2
El servicio construye el Observable
return this.http.post<Artista>(url, datos)  ← aún no envía nada
3
.subscribe() enciende el Observable
.subscribe({ next: ..., error: ... })  ← aquí se envía la petición HTTP
4
Petición en vuelo hacia el servidor
POST https://artistas.api/artistas → aguardando respuesta…
✓
Respuesta del servidor
next() o error() según el resultado

Consola del componente

// Esperando acción del usuario…

El patrón completo en contexto

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.

artista.service.ts  —  el único que habla con la red

@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
    );
  }
}

artista-form.component.ts  —  orquesta, no habla con la red

@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);
        }
      });
  }
}
🔑
La regla de oro: el componente nunca inyecta 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.

Errores comunes en este release

❌ Olvidar el .subscribe()

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.

❌ Inyectar HttpClient 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.

❌ No recargar el resource después del POST

El artista se crea en el servidor, pero artistasResource.value() sigue mostrando los datos de antes. Después del next() exitoso, llame artistasResource.reload().

✓ ¿Cómo detectar que el servidor respondió?

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.

Autoevaluación

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?

El Observable es frío: sin 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?

Compila y funciona, pero viola la arquitectura por capas. La presentación no debe saber de dónde vienen los datos ni cómo se envían. Si el back cambia (URL, headers, autenticación), habría que tocar el componente — que debería ser ajeno a eso.