En esta página
HttpClient: consumir APIs REST
HttpClient en Angular
HttpClient es el servicio integrado de Angular para comunicarse con APIs REST. Devuelve Observables tipados y soporta interceptores, manejo de errores y transformaciones.
Configurar HttpClient
En app.config.ts, provee el cliente HTTP:
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withFetch(), // Usa Fetch API nativa
withInterceptors([authInterceptor]),
),
],
};Métodos HTTP
HttpClient ofrece métodos para cada verbo HTTP:
const http = inject(HttpClient);
// GET - Obtener datos
http.get<Usuario[]>('/api/usuarios');
// POST - Crear recurso
http.post<Usuario>('/api/usuarios', { nombre: 'Ana' });
// PUT - Reemplazar recurso completo
http.put<Usuario>('/api/usuarios/1', datosCompletos);
// PATCH - Actualizar parcialmente
http.patch<Usuario>('/api/usuarios/1', { nombre: 'Ana Maria' });
// DELETE - Eliminar recurso
http.delete<void>('/api/usuarios/1');Parametros de consulta
Usa HttpParams para agregar query parameters:
import { HttpParams } from '@angular/common/http';
const params = new HttpParams()
.set('página', 1)
.set('limite', 20)
.set('orden', 'fecha');
http.get<Resultado>('/api/buscar', { params });
// GET /api/buscar?página=1&limite=20&orden=fechaHeaders personalizados
import { HttpHeaders } from '@angular/common/http';
const headers = new HttpHeaders()
.set('Authorization', `Bearer ${token}`)
.set('Accept-Language', 'es');
http.get('/api/datos', { headers });Interceptores funcionales
Los interceptores procesan TODAS las peticiones y respuestas HTTP:
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const auth = inject(AuthService);
const token = auth.token();
if (token) {
const reqConAuth = req.clone({
setHeaders: { Authorization: `Bearer ${token}` },
});
return next(reqConAuth);
}
return next(req);
};Registra interceptores en la configuración:
provideHttpClient(
withInterceptors([authInterceptor, loggingInterceptor]),
)Manejo de errores
Usa catchError de RxJS para manejar errores HTTP:
import { catchError } from 'rxjs/operators';
import { of, throwError } from 'rxjs';
obtenerUsuario(id: number) {
return this.http.get<Usuario>(`/api/usuarios/${id}`).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 404) {
return of(null); // Devolver null si no existe
}
return throwError(() => error); // Re-lanzar otros errores
}),
);
}HttpClient con resource
Puedes combinar HttpClient con rxResource para carga reactiva:
import { rxResource } from '@angular/core/rxjs-interop';
readonly usuarioId = signal(1);
readonly usuario = rxResource({
request: () => ({ id: this.usuarioId() }),
loader: ({ request }) =>
this.http.get<Usuario>(`/api/usuarios/${request.id}`),
});Buenas prácticas
- Tipar las respuestas — Siempre usa genericos:
get<MiTipo>() - Centralizar en servicios — No llames HttpClient desde componentes
- Manejar errores — Usa
catchErrorpara respuestas fallidas - Usar interceptores — Para autenticación, logging y retry
Práctica
- Crea un servicio CRUD: Implementa un servicio con metodos
obtenerTodos(),obtenerPorId(),crear()yeliminar()usandoHttpClientcontrahttps://jsonplaceholder.typicode.com/posts. Tipa todas las respuestas con genericos. - Agrega un interceptor de logging: Crea un interceptor funcional que registre en consola la URL y el metodo de cada peticion HTTP. Registralo con
withInterceptors()en la configuracion. - Maneja errores con catchError: En el metodo
obtenerPorId(), usacatchErrorpara devolvernullcuando el servidor responda con 404 y re-lanzar otros errores.
En la siguiente leccion aprenderemos los operadores esenciales de RxJS para transformar y combinar flujos de datos.
import { Injectable, inject, signal, computed } from '@angular/core';
import { HttpClient, HttpParams, HttpErrorResponse } from '@angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';
import { of } from 'rxjs';
interface Articulo {
id: number;
título: string;
contenido: string;
autor: string;
fecha: string;
}
interface PaginaResponse {
datos: Articulo[];
total: number;
página: number;
}
@Injectable({ providedIn: 'root' })
export class ArticulosService {
private readonly http = inject(HttpClient);
private readonly baseUrl = '/api/articulos';
private readonly _cargando = signal(false);
readonly cargando = this._cargando.asReadonly();
obtenerTodos(página = 1, limite = 10) {
this._cargando.set(true);
const params = new HttpParams()
.set('página', página)
.set('limite', limite);
return this.http
.get<PaginaResponse>(this.baseUrl, { params })
.pipe(
tap(() => this._cargando.set(false)),
catchError((error: HttpErrorResponse) => {
this._cargando.set(false);
console.error('Error al cargar articulos:', error.message);
return of({ datos: [], total: 0, página: 1 });
}),
);
}
obtenerPorId(id: number) {
return this.http.get<Articulo>(`${this.baseUrl}/${id}`);
}
crear(articulo: Omit<Articulo, 'id'>) {
return this.http.post<Articulo>(this.baseUrl, articulo);
}
actualizar(id: number, cambios: Partial<Articulo>) {
return this.http.patch<Articulo>(
`${this.baseUrl}/${id}`,
cambios,
);
}
eliminar(id: number) {
return this.http.delete<void>(`${this.baseUrl}/${id}`);
}
}
Inicia sesión para guardar tu progreso