Overview
The HttpClient service provides a powerful and flexible API for making HTTP requests in Angular applications. It returns RxJS Observables, enabling reactive programming patterns and composable data streams.
Setup
Standalone applications
Provide HttpClient in your application configuration:
import { ApplicationConfig } from '@angular/core' ;
import { provideHttpClient } from '@angular/common/http' ;
export const appConfig : ApplicationConfig = {
providers: [
provideHttpClient ()
]
};
Module-based applications
Import HttpClientModule in your application module:
import { NgModule } from '@angular/core' ;
import { HttpClientModule } from '@angular/common/http' ;
@ NgModule ({
imports: [ HttpClientModule ],
// ...
})
export class AppModule { }
For server-side rendering applications, use withFetch() for better performance: provideHttpClient ( withFetch ())
Injecting HttpClient
Inject HttpClient into your services or components:
import { Injectable , inject } 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 http = inject ( HttpClient );
private apiUrl = 'https://api.example.com' ;
getUsers () : Observable < User []> {
return this . http . get < User []>( ` ${ this . apiUrl } /users` );
}
}
HTTP Methods
GET requests
Retrieve data from the server:
// Simple GET request
http . get < User []>( '/api/users' ). subscribe ( users => {
console . log ( 'Users:' , users );
});
// GET with query parameters
http . get < User []>( '/api/users' , {
params: { role: 'admin' , active: true }
}). subscribe ( users => {
console . log ( 'Admin users:' , users );
});
// GET with headers
http . get < User >( '/api/users/1' , {
headers: { 'Authorization' : 'Bearer token' }
}). subscribe ( user => {
console . log ( 'User:' , user );
});
POST requests
Send data to create new resources:
const newUser : User = {
id: 0 ,
name: 'John Doe' ,
email: 'john@example.com'
};
http . post < User >( '/api/users' , newUser ). subscribe ({
next : ( user ) => console . log ( 'Created user:' , user ),
error : ( error ) => console . error ( 'Error:' , error )
});
// POST with options
http . post < User >( '/api/users' , newUser , {
headers: { 'Content-Type' : 'application/json' },
observe: 'response'
}). subscribe ( response => {
console . log ( 'Status:' , response . status );
console . log ( 'User:' , response . body );
});
PUT requests
Update existing resources:
const updatedUser : User = {
id: 1 ,
name: 'Jane Doe' ,
email: 'jane@example.com'
};
http . put < User >( '/api/users/1' , updatedUser ). subscribe ({
next : ( user ) => console . log ( 'Updated user:' , user ),
error : ( error ) => console . error ( 'Update failed:' , error )
});
PATCH requests
Partially update resources:
// Update only the name field
http . patch < User >( '/api/users/1' , { name: 'New Name' }). subscribe ( user => {
console . log ( 'Patched user:' , user );
});
DELETE requests
Remove resources:
http . delete ( `/api/users/ ${ userId } ` ). subscribe ({
next : () => console . log ( 'User deleted' ),
error : ( error ) => console . error ( 'Delete failed:' , error )
});
// DELETE with response body
http . delete <{ message : string }>( `/api/users/ ${ userId } ` ). subscribe ( result => {
console . log ( result . message );
});
Request Options
Query parameters
Add URL query parameters using the params option:
import { HttpParams } from '@angular/common/http' ;
// Using object notation
http . get ( '/api/users' , {
params: {
page: 1 ,
limit: 10 ,
sort: 'name'
}
});
// Using HttpParams for complex scenarios
let params = new HttpParams ()
. set ( 'page' , '1' )
. set ( 'limit' , '10' )
. append ( 'tags' , 'angular' )
. append ( 'tags' , 'typescript' );
http . get ( '/api/posts' , { params });
// URL: /api/posts?page=1&limit=10&tags=angular&tags=typescript
Customize request headers:
import { HttpHeaders } from '@angular/common/http' ;
// Using object notation
http . get ( '/api/users' , {
headers: {
'Authorization' : 'Bearer token' ,
'X-Custom-Header' : 'value'
}
});
// Using HttpHeaders
const headers = new HttpHeaders ()
. set ( 'Authorization' , 'Bearer token' )
. set ( 'Content-Type' , 'application/json' );
http . post ( '/api/users' , data , { headers });
Response types
Specify the expected response type:
// JSON (default)
http . get < User >( '/api/users/1' );
// Text
http . get ( '/api/data' , { responseType: 'text' }). subscribe ( text => {
console . log ( text );
});
// ArrayBuffer
http . get ( '/api/file' , { responseType: 'arraybuffer' }). subscribe ( buffer => {
const blob = new Blob ([ buffer ]);
});
// Blob
http . get ( '/api/image' , { responseType: 'blob' }). subscribe ( blob => {
const url = URL . createObjectURL ( blob );
});
Observing responses
Control what information is returned:
// Body only (default)
http . get < User >( '/api/users/1' ). subscribe ( user => {
console . log ( user );
});
// Full response with headers and status
http . get < User >( '/api/users/1' , { observe: 'response' }). subscribe ( response => {
console . log ( 'Status:' , response . status );
console . log ( 'Headers:' , response . headers . get ( 'X-Custom' ));
console . log ( 'Body:' , response . body );
});
// Event stream for progress tracking
http . get ( '/api/large-file' , {
observe: 'events' ,
reportProgress: true
}). subscribe ( event => {
if ( event . type === HttpEventType . DownloadProgress ) {
const progress = event . loaded / ( event . total || 1 ) * 100 ;
console . log ( `Download: ${ progress } %` );
}
});
Working with Observables
Basic subscription
import { Component , OnInit , inject } from '@angular/core' ;
import { HttpClient } from '@angular/common/http' ;
@ Component ({
selector: 'app-users' ,
template: `
<div *ngFor="let user of users">
{{ user.name }}
</div>
`
})
export class UsersComponent implements OnInit {
private http = inject ( HttpClient );
users : User [] = [];
ngOnInit () {
this . http . get < User []>( '/api/users' ). subscribe ({
next : ( users ) => this . users = users ,
error : ( error ) => console . error ( 'Error loading users:' , error )
});
}
}
RxJS operators
Transform HTTP responses using RxJS operators:
import { map , filter , catchError , retry , timeout } from 'rxjs/operators' ;
import { of } from 'rxjs' ;
// Transform the response
http . get < User []>( '/api/users' ). pipe (
map ( users => users . filter ( u => u . active )),
map ( users => users . sort (( a , b ) => a . name . localeCompare ( b . name )))
). subscribe ( sortedActiveUsers => {
console . log ( sortedActiveUsers );
});
// Retry on failure
http . get < User []>( '/api/users' ). pipe (
retry ( 3 ),
catchError ( error => {
console . error ( 'Failed after 3 retries:' , error );
return of ([]); // Return empty array as fallback
})
). subscribe ( users => {
console . log ( users );
});
// Timeout
http . get < User []>( '/api/users' ). pipe (
timeout ( 5000 ),
catchError ( error => {
console . error ( 'Request timed out' );
return of ([]);
})
). subscribe ( users => {
console . log ( users );
});
Combining multiple requests
import { forkJoin , combineLatest } from 'rxjs' ;
// Wait for all requests to complete
forkJoin ({
users: http . get < User []>( '/api/users' ),
posts: http . get < Post []>( '/api/posts' ),
comments: http . get < Comment []>( '/api/comments' )
}). subscribe (({ users , posts , comments }) => {
console . log ( 'All data loaded:' , users , posts , comments );
});
// Combine latest values
combineLatest ([
http . get < User []>( '/api/users' ),
http . get < Config >( '/api/config' )
]). subscribe (([ users , config ]) => {
console . log ( 'Users and config:' , users , config );
});
Sequential requests
import { switchMap , mergeMap } from 'rxjs/operators' ;
// Switch to new request (cancels previous)
http . get < User >( '/api/users/1' ). pipe (
switchMap ( user => http . get < Post []>( `/api/users/ ${ user . id } /posts` ))
). subscribe ( posts => {
console . log ( 'User posts:' , posts );
});
// Process all requests
http . get < User []>( '/api/users' ). pipe (
mergeMap ( users => users ),
mergeMap ( user => http . get < Post []>( `/api/users/ ${ user . id } /posts` ))
). subscribe ( posts => {
console . log ( 'Posts:' , posts );
});
Type safety
Provide type information for responses:
interface ApiResponse < T > {
data : T ;
status : string ;
timestamp : number ;
}
interface User {
id : number ;
name : string ;
email : string ;
}
// Type-safe request
http . get < ApiResponse < User >>( '/api/users/1' ). subscribe ( response => {
const user = response . data ;
console . log ( user . name ); // TypeScript knows about .name
});
// Array of users
http . get < User []>( '/api/users' ). subscribe ( users => {
users . forEach ( user => {
console . log ( user . email ); // Type-safe access
});
});
Advanced options
Request credentials
// Include credentials in cross-origin requests
http . get ( '/api/users' , {
withCredentials: true
}). subscribe ();
// Using Fetch API credentials option
http . get ( '/api/users' , {
credentials: 'include' // 'omit' | 'same-origin' | 'include'
}). subscribe ();
Request timeout
// Set timeout in milliseconds
http . get ( '/api/users' , {
timeout: 5000 // 5 seconds
}). subscribe ({
error : ( error ) => console . error ( 'Request timed out' )
});
Transfer cache (SSR)
// Cache responses for server-side rendering
http . get ( '/api/users' , {
transferCache: true
}). subscribe ();
// Cache with specific headers
http . get ( '/api/users' , {
transferCache: {
includeHeaders: [ 'Authorization' , 'X-Custom-Header' ]
}
}). subscribe ();
Best practices
Use services for HTTP calls Encapsulate HTTP logic in dedicated services rather than making calls directly from components.
Provide type information Always specify generic types for type-safe responses: http.get<User[]>('/api/users')
Handle errors appropriately Use error handlers or the catchError operator to gracefully handle failed requests.
HTTP requests are not executed until you subscribe to the Observable. Always remember to subscribe, or use operators like toPromise() or the async pipe in templates.
Unsubscribe when needed For long-lived subscriptions in components, unsubscribe in ngOnDestroy or use the async pipe which automatically unsubscribes.
Next steps
Interceptors Transform requests and responses globally with HTTP interceptors.
Error handling Handle HTTP errors and implement retry logic.