HttpClient y provideHttpClient
HttpClient es el servicio principal de Angular para realizar peticiones HTTP a servidores remotos. Se trata del cliente HTTP oficial que reemplazó al antiguo Http service, proporcionando una API más moderna y robusta para comunicarse con APIs REST.
Este servicio está construido sobre observables de RxJS, lo que significa que todas las peticiones devuelven observables que podemos suscribir y transformar utilizando los operadores que hemos visto anteriormente. Esta integración nativa con RxJS hace que HttpClient sea especialmente útil para manejar operaciones asíncronas de manera reactiva.
Configuración con provideHttpClient
En Angular 20, la configuración de HttpClient se realiza utilizando la función provideHttpClient() en el archivo app.config.ts
. Esta aproximación moderna se alinea con la arquitectura standalone que Angular ha adoptado como estándar.
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient()
]
};
La función provideHttpClient() registra automáticamente todos los servicios necesarios para realizar peticiones HTTP en el sistema de inyección de dependencias de Angular. Una vez configurado, HttpClient estará disponible en toda la aplicación.
Arquitectura moderna vs versiones anteriores
Esta configuración moderna representa un cambio significativo respecto a versiones anteriores de Angular, donde era necesario importar HttpClientModule
en los módulos NgModule. Con la arquitectura standalone actual, la configuración es más directa y centralizada.
// Antes (con NgModules) - NO usar en Angular 20
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [HttpClientModule]
})
// Ahora (Angular 20) - Configuración moderna
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient()
]
};
Inyección del servicio HttpClient
Una vez configurado el proveedor, podemos inyectar HttpClient en nuestros componentes y servicios utilizando cualquiera de los métodos de inyección que hemos aprendido. Recordemos que tenemos dos aproximaciones principales:
Inyección por constructor:
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-user-list',
standalone: true,
template: `<p>Lista de usuarios</p>`
})
export class UserListComponent {
constructor(private http: HttpClient) {}
}
Inyección con inject():
import { Component, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-user-list',
standalone: true,
template: `<p>Lista de usuarios</p>`
})
export class UserListComponent {
private http = inject(HttpClient);
}
Servicios dedicados para HTTP
La práctica recomendada es encapsular las peticiones HTTP en servicios dedicados en lugar de realizarlas directamente en los componentes. Esto mejora la separación de responsabilidades y facilita el testing.
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class UserService {
private http = inject(HttpClient);
private apiUrl = 'https://jsonplaceholder.typicode.com';
// Aquí definiremos nuestros métodos para peticiones HTTP
}
Con esta estructura, los componentes se suscriben a los métodos del servicio, mientras que el servicio se encarga de toda la lógica relacionada con HTTP. Esto mantiene los componentes enfocados en la presentación y la interacción con el usuario.
Tipado con TypeScript
Una de las grandes ventajas de HttpClient es su excelente integración con TypeScript. Podemos tipar tanto las peticiones como las respuestas, obteniendo autocompletado y verificación de tipos en tiempo de compilación.
// Definimos la estructura de los datos que esperamos
interface User {
id: number;
name: string;
email: string;
username: string;
}
@Injectable({
providedIn: 'root'
})
export class UserService {
private http = inject(HttpClient);
// HttpClient<T> nos permite especificar el tipo de respuesta esperada
// Esto proporcionará intellisense y verificación de tipos
}
Este tipado estático nos ayuda a detectar errores durante el desarrollo y mejora significativamente la experiencia de programación, especialmente cuando trabajamos con APIs complejas que devuelven estructuras de datos específicas.
HttpClient está ahora listo para realizar peticiones HTTP. En la siguiente sección veremos cómo utilizar este servicio para realizar peticiones GET y manejar las respuestas de manera efectiva.
Peticiones GET básicas
Las peticiones GET son el tipo más común de petición HTTP, utilizadas para obtener datos del servidor sin modificar el estado del recurso. Con HttpClient, realizar estas peticiones es sencillo y sigue el patrón reactivo de Angular.
Sintaxis básica de peticiones GET
El método get() de HttpClient devuelve un observable que debemos suscribir para recibir la respuesta. La sintaxis básica es la siguiente:
// En un servicio
@Injectable({
providedIn: 'root'
})
export class UserService {
private http = inject(HttpClient);
private apiUrl = 'https://jsonplaceholder.typicode.com';
getUsers() {
return this.http.get(`${this.apiUrl}/users`);
}
}
Tipado de respuestas
Una de las características más útiles de HttpClient es la posibilidad de tipar las respuestas. Esto nos proporciona autocompletado y verificación de tipos durante el desarrollo:
interface User {
id: number;
name: string;
email: string;
username: string;
}
@Injectable({
providedIn: 'root'
})
export class UserService {
private http = inject(HttpClient);
private apiUrl = 'https://jsonplaceholder.typicode.com';
getUsers() {
return this.http.get<User[]>(`${this.apiUrl}/users`);
}
getUserById(id: number) {
return this.http.get<User>(`${this.apiUrl}/users/${id}`);
}
}
El tipo genérico <User[]>
indica que esperamos un array de objetos User, mientras que <User>
especifica un único objeto User. Esto mejora significativamente la experiencia de desarrollo.
Suscripción en componentes
Los componentes deben suscribirse a los observables devueltos por HttpClient para recibir los datos. La suscripción se realiza típicamente en los hooks de ciclo de vida:
@Component({
selector: 'app-user-list',
standalone: true,
imports: [CommonModule],
template: `
@if (users.length > 0) {
<ul>
@for (user of users; track user.id) {
<li>{{ user.name }} - {{ user.email }}</li>
}
</ul>
} @else {
<p>Cargando usuarios...</p>
}
`
})
export class UserListComponent implements OnInit {
private userService = inject(UserService);
users: User[] = [];
ngOnInit() {
this.userService.getUsers().subscribe({
next: (data) => {
this.users = data;
}
});
}
}
Patrón Observer en suscripciones
Las suscripciones a observables pueden manejar tres estados diferentes utilizando el patrón Observer:
ngOnInit() {
this.userService.getUsers().subscribe({
next: (data) => {
// Se ejecuta cuando llegan los datos exitosamente
this.users = data;
console.log('Datos recibidos:', data);
},
error: (error) => {
// Se ejecuta si ocurre un error en la petición
console.error('Error al obtener usuarios:', error);
},
complete: () => {
// Se ejecuta cuando el observable se completa
console.log('Petición completada');
}
});
}
Gestión de suscripciones
Es importante gestionar las suscripciones correctamente para evitar memory leaks. Una práctica común es almacenar la suscripción y cancelarla en el hook ngOnDestroy
:
export class UserListComponent implements OnInit, OnDestroy {
private userService = inject(UserService);
private subscription?: Subscription;
users: User[] = [];
ngOnInit() {
this.subscription = this.userService.getUsers().subscribe({
next: (data) => {
this.users = data;
}
});
}
ngOnDestroy() {
this.subscription?.unsubscribe();
}
}
Peticiones con parámetros de consulta
Las query parameters se pueden añadir de varias maneras. La más directa es incluirlas en la URL, pero HttpClient también proporciona un objeto de opciones:
// Método 1: Directamente en la URL
getUsersByRole(role: string) {
return this.http.get<User[]>(`${this.apiUrl}/users?role=${role}`);
}
// Método 2: Usando HttpParams (más limpio)
import { HttpParams } from '@angular/common/http';
getUsersFiltered(role: string, active: boolean) {
const params = new HttpParams()
.set('role', role)
.set('active', active.toString());
return this.http.get<User[]>(`${this.apiUrl}/users`, { params });
}
Headers personalizados
Podemos añadir headers personalizados a nuestras peticiones GET utilizando el objeto de opciones:
import { HttpHeaders } from '@angular/common/http';
getUsersWithAuth() {
const headers = new HttpHeaders({
'Authorization': 'Bearer ' + this.getToken(),
'Content-Type': 'application/json'
});
return this.http.get<User[]>(`${this.apiUrl}/users`, { headers });
}
private getToken(): string {
return localStorage.getItem('auth-token') || '';
}
Ejemplo práctico completo
Aquí tenemos un ejemplo completo que muestra cómo estructurar un servicio y componente para peticiones GET:
// user.service.ts
@Injectable({
providedIn: 'root'
})
export class UserService {
private http = inject(HttpClient);
private apiUrl = 'https://jsonplaceholder.typicode.com';
getUsers() {
return this.http.get<User[]>(`${this.apiUrl}/users`);
}
getUserById(id: number) {
return this.http.get<User>(`${this.apiUrl}/users/${id}`);
}
}
// user-detail.component.ts
@Component({
selector: 'app-user-detail',
standalone: true,
template: `
@if (user) {
<div class="user-card">
<h2>{{ user.name }}</h2>
<p>Email: {{ user.email }}</p>
<p>Username: {{ user.username }}</p>
</div>
} @else {
<p>Cargando detalles del usuario...</p>
}
`
})
export class UserDetailComponent implements OnInit {
private userService = inject(UserService);
private route = inject(ActivatedRoute);
user: User | null = null;
ngOnInit() {
const userId = Number(this.route.snapshot.paramMap.get('id'));
this.userService.getUserById(userId).subscribe({
next: (userData) => {
this.user = userData;
}
});
}
}
Consideraciones importantes
Al trabajar con peticiones GET, es importante recordar que:
- Las peticiones HTTP son asíncronas por naturaleza, por lo que siempre trabajamos con observables
- Los observables de HttpClient son "cold", lo que significa que no se ejecutan hasta que alguien se suscribe
- Cada suscripción crea una nueva petición HTTP, a menos que utilicemos operadores como
share()
oshareReplay()
- Es fundamental gestionar las suscripciones correctamente para evitar memory leaks
Con estos fundamentos, ya podemos realizar peticiones GET efectivas en nuestras aplicaciones Angular, obteniendo datos de APIs de manera reactiva y tipada.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Angular
Documentación oficial de Angular
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Angular es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Angular
Explora más contenido relacionado con Angular y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender la configuración moderna de HttpClient con provideHttpClient en Angular 20.
- Aprender a inyectar y utilizar HttpClient en componentes y servicios.
- Realizar peticiones GET básicas y tipadas con TypeScript.
- Gestionar suscripciones a observables para evitar memory leaks.
- Añadir parámetros de consulta y headers personalizados en peticiones HTTP.