HttpClient
| Since: | Angular 14(2022) |
|---|
HttpClient is Angular's built-in HTTP client for communicating with backend APIs. It provides methods for the standard HTTP verbs (GET, POST, PUT, PATCH, DELETE) that return Observables. To use it, call provideHttpClient() in your application configuration (Standalone API) or import HttpClientModule in your NgModule. Responses are typed using TypeScript generics, and error handling is done with RxJS operators such as catchError.
Setup
// app.config.ts (Standalone API)
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [provideHttpClient()],
};
HttpClient Methods
| Method | Overview |
|---|---|
get<T>(url, options?) | Sends a GET request and returns an Observable of type T. |
post<T>(url, body, options?) | Sends a POST request with a body and returns an Observable of type T. |
put<T>(url, body, options?) | Sends a PUT request (full replacement). |
patch<T>(url, body, options?) | Sends a PATCH request (partial update). |
delete<T>(url, options?) | Sends a DELETE request. |
head(url, options?) | Sends a HEAD request to retrieve response headers only. |
Sample Code
A user service with full CRUD operations using HttpClient.
// user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
interface User {
id: number;
name: string;
email: string;
}
@Injectable({ providedIn: 'root' })
export class UserService {
private apiUrl = 'https://api.example.com/users';
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl);
}
getUser(id: number): Observable<User> {
return this.http.get<User>(`${this.apiUrl}/${id}`);
}
createUser(user: Omit<User, 'id'>): Observable<User> {
return this.http.post<User>(this.apiUrl, user);
}
updateUser(id: number, user: Partial<User>): Observable<User> {
return this.http.patch<User>(`${this.apiUrl}/${id}`, user);
}
deleteUser(id: number): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`);
}
}
A user list component that fetches data and handles loading and error states.
// user-list.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { NgFor, NgIf } from '@angular/common';
import { UserService } from './user.service';
import { Subscription } from 'rxjs';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-user-list',
template: `
<p *ngIf="isLoading">Loading...</p>
<p *ngIf="error">Error: {{ error }}</p>
<ul *ngIf="!isLoading && !error">
<li *ngFor="let user of users">
{{ user.name }} — {{ user.email }}
</li>
</ul>
`,
imports: [NgFor, NgIf],
standalone: true,
})
export class UserListComponent implements OnInit, OnDestroy {
users: User[] = [];
isLoading = false;
error = '';
private subscription!: Subscription;
constructor(private userService: UserService) {}
ngOnInit(): void {
this.isLoading = true;
this.subscription = this.userService.getUsers().subscribe({
next: (users) => {
this.users = users;
this.isLoading = false;
},
error: (err) => {
this.error = err.message;
this.isLoading = false;
},
});
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
Adding authorization headers and query parameters with HttpHeaders and HttpParams.
// search.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
interface SearchResult {
items: { id: number; name: string }[];
total: number;
}
@Injectable({ providedIn: 'root' })
export class SearchService {
private apiUrl = 'https://api.example.com/search';
constructor(private http: HttpClient) {}
search(query: string, page: number, token: string): Observable<SearchResult> {
const headers = new HttpHeaders({ Authorization: `Bearer ${token}` });
const params = new HttpParams().set('q', query).set('page', String(page));
return this.http.get<SearchResult>(this.apiUrl, { headers, params });
}
}
Notes
| Item | Description |
|---|---|
| Setup | Standalone API: provideHttpClient() in app.config.ts. NgModule: import HttpClientModule. |
| Observable — must subscribe | HttpClient methods return cold Observables. Nothing happens until you subscribe (or use async pipe). |
| Unsubscribe | Unsubscribe in ngOnDestroy to prevent memory leaks. Alternatively use takeUntilDestroyed() or AsyncPipe. |
| Error handling | Handle errors in the error callback or with the catchError RxJS operator. |
| Type safety | Pass a generic type to HttpClient methods (e.g., get<User[]>) to get type-checked responses. |
Summary
HttpClient is the standard way to make HTTP requests in Angular. Set it up with provideHttpClient() in the app config, inject it into a service, and call typed methods like get<T> and post<T> that return Observables. Handle loading and error states in the subscriber's next and error callbacks, and always unsubscribe to avoid memory leaks.
For intercepting and transforming requests globally, see HTTP Interceptors. For consuming the Observables directly in templates, see AsyncPipe.
Common Mistake: Forgetting provideHttpClient()
If provideHttpClient() is not registered, Angular cannot resolve HttpClient from the injector, causing a "NullInjectorError: No provider for HttpClient" at runtime.
// NG: provideHttpClient() not registered
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes)],
};
// OK: add provideHttpClient()
import { provideHttpClient } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideHttpClient()],
};
Common Mistake: Not subscribing to the Observable
HttpClient methods return cold Observables — no HTTP request is sent until something subscribes. Calling the method without subscribing silently does nothing.
// NG: method called but not subscribed — request never fires
ngOnInit(): void {
this.userService.getUsers(); // no subscribe — nothing happens
}
// OK: subscribe to trigger the request
ngOnInit(): void {
this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
Common Mistake: Not unsubscribing and causing a memory leak
Subscriptions to long-lived Observables must be unsubscribed when the component is destroyed. Failing to do so keeps the callback alive and can cause stale state updates or memory leaks.
// NG: subscription is never unsubscribed
ngOnInit(): void {
this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
// OK: store and unsubscribe in ngOnDestroy
private sub!: Subscription;
ngOnInit(): void {
this.sub = this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
ngOnDestroy(): void {
this.sub.unsubscribe();
}
If you find any errors or copyright issues, please contact us.