Angular 21 de Cero a Experto / HTTP y datos
HttpClient: hablar con el backend
Tu app deja de ser un juguete cuando habla con un servidor: cargar los gastos reales,
guardarlos, borrarlos. HttpClient es el cliente HTTP de Angular —integrado, tipado y basado
en Observables—. Hoy conectas "Mi Bolsillo" con un backend: haces peticiones GET, POST, PUT y
DELETE, tipas las respuestas, y entiendes por qué cada petición es un Observable.
El mensajero entre tu app y el servidor
Configurar HttpClient
En Angular standalone, habilitas HttpClient en el arranque con provideHttpClient:
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withFetch } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()), // withFetch: usa la API fetch moderna
],
};Luego lo inyectas en cualquier servicio:
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
export interface Gasto { id: number; nombre: string; valor: number; categoria: string; }
@Injectable({ providedIn: 'root' })
export class ApiGastosService {
private http = inject(HttpClient);
private url = '/api/gastos';
listar() { return this.http.get<Gasto[]>(this.url); }
}Ese <Gasto[]> es clave: le dices a HttpClient qué forma tiene la respuesta, y trabajas con
datos tipados en toda tu app. (Ojo: es una PROMESA de tipo, no una validación en runtime —el
servidor podría mentir—; para validar de verdad, usa Zod en la frontera, como en el SC-03.)
Los cuatro verbos
@Injectable({ providedIn: 'root' })
export class ApiGastosService {
private http = inject(HttpClient);
private url = '/api/gastos';
listar() { return this.http.get<Gasto[]>(this.url); }
obtener(id: number) { return this.http.get<Gasto>(`${this.url}/${id}`); }
crear(g: Omit<Gasto, 'id'>) { return this.http.post<Gasto>(this.url, g); }
actualizar(g: Gasto) { return this.http.put<Gasto>(`${this.url}/${g.id}`, g); }
eliminar(id: number) { return this.http.delete<void>(`${this.url}/${id}`); }
}Cada método devuelve un Observable. El post y el put reciben el cuerpo (el objeto a
enviar) como segundo argumento; HttpClient lo serializa a JSON por ti. El Omit<Gasto, 'id'>
en crear expresa que al crear aún no hay id —lo asigna el servidor—.
Recuerda: es un Observable perezoso
Como cada método devuelve un Observable, no pasa nada hasta que alguien se suscribe:
const api = inject(ApiGastosService);
api.listar(); // ❌ NO hace la petición: nadie se suscribió
api.listar().subscribe((gastos) => console.log(gastos)); // ✅ ahora sí
// pero en un componente NO te suscribes a mano: usas toSignal (próxima lección)Esto sorprende a quien viene de fetch() (que corre al invocarse). En Angular, el Observable
es una RECETA de la petición; se ejecuta al suscribirse. En la práctica no llamarás
subscribe a mano casi nunca: toSignal (para leer datos) y HttpClient dentro de un
switchMap/exhaustMap (para acciones) gestionan la suscripción por ti.
Query params, headers y opciones
// query params: /api/gastos?categoria=comida&orden=valor
this.http.get<Gasto[]>(this.url, {
params: { categoria: 'comida', orden: 'valor' },
});
// headers (por ejemplo, para autenticación puntual)
this.http.get<Gasto[]>(this.url, {
headers: { Authorization: `Bearer ${token}` },
});HttpClient construye la query string por ti a partir del objeto params. (Para el token de
auth, verás que es mejor un INTERCEPTOR que añadirlo a mano en cada petición.)
Antes (HttpClientModule) vs Ahora (provideHttpClient)
¿Por qué `api.listar()` no hace la petición hasta que alguien se suscribe?
Mini-reto
Diseña un ApiCategoriasService con providedIn: 'root': 1) inyecta HttpClient; 2) métodos
listar() (GET /api/categorias), crear(nombre) (POST) y eliminar(id) (DELETE), todos
tipados; 3) un método buscar(termino) que use query params. Anota por qué ninguno hace la
petición hasta que se consuma con toSignal o subscribe.
Qué sigue
Ya haces peticiones tipadas. Pero una petición real tiene tres momentos —cargando, error,
datos— y el usuario debe ver cada uno. La próxima lección construye el patrón de estados de
carga con señales: convertir un Observable de HttpClient en un estado reactivo que el
template muestra con claridad.