HttpClient_ Angular
Angualar HttpClient - Complate interview Guide
What is HttpClient?
HttpClient: is a built-in Angualr service for making HTTP requests to backend APIs. It's part of @angular/commom/http module and provides a simplified API for HTTP functinality.
Package Location
import { HttpClient } form '@angular/common/http';
Key Features of HttpClient
- ✅ Typed Response: - Supports TypeScript generics for type safe
- ✅ Observable: - Return RxJS Observable (cancellable, composable)
- ✅ Request/Response Intereception: - Via HTTP Interceptors
- ✅ Testability: - Easy to mock and test with HttpClientTestingModule
- ✅ Progress Events: - Track Upload/download progress
- ✅ Error Handeling: - Structured error handling with HttpErrorResponse
- ✅ Request Cancellation: - Using unsubscribe
- ✅ Automatic JSON Parsing: - Parses JSON response automatically
HttpClient vs Http (Deprecated)
| Feature | HttpClient (current) | Http (old) |
|---|---|---|
| Package | @angular/common/http | @angular/http |
| Response Type | Observable | Observable |
| JSON Parsing | ✅ Automatic | ❌ Manual (.json()) |
| Interceptors | ✅ Yes | ❌ No |
| Type Safety | ✅ Active | ❌ Deprecated |
| Request/Response | Immutable | Mutable |
| Status | ✅ Active | ❌ Deprecated |
| Tree-Shakable | ✅ Yes | ❌ No |
Setup HttpClient in Angular Application
Method 1: Using provideHttpClient (Standalone - Modern)
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import {ProvideHttpClient, withInterceptors} from '@angular/common/http';
import { authInterceptor } from './interceptors/auth.interceptor';
import { loggingInterceptor } from './interceptors/logging.Interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withInterceptors([
loggingInterceptor,
authInterceptor
])
)
]
};
Method 2: Using HttpClientModule (NgMoudule - lagacy)
// app.module.ts
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule
],
providers: []
})
export class AppModule { }
HTTP Methods Available
| Method | Purpose | Idempotent | Safe | Example Use case | | GET | Retrieve data | ✅ Yes | ✅ yes | Fetch user list | | POST | Create resource | ❌ No | ❌ No | Create user | | PUT | Replace resource | ✅ Yes | ❌ No | Update user completely | | PATCH | Partica Update | ❌ No | ❌ No | Update some field only | | DELETE | Delete resource | ✅ Yes | ❌ No | Delete user | | HEAD | Get headers only | ✅ Yes | ✅ Yes | check if resource exists | | OPTIONS | Get all methods | ✅ Yes | ✅ Yes | CORS preflight |
Note:
- Idempotent: Multiple identical requests have same effect as single request
- Safe: Request doesn't modify server state
Complate Implementation Examples
1. Create User Service with All HTTP Methods
// ../services/user.service.ts
import { Injectable } from '@angualar/core';
import { HttpClient, HttpHeaders, HttpParams, HttpErrorResponse } from '@angular/commom/http';
import { Observable, throwError } from 'RxJs';
import { catchError, retry, map, tap } from 'rxjs/operators';
// Define Interfaces for type safe
export interface User {
id?: number;
name: string;
email: string;
phone?: string;
website?: string;
address?: {
street: string;
city: string;
ZipCode: string;
};
}
export interface ApiResponse<T> {
data: T;
message: string;
status: number;
}
export interface PaginatedResponse<T> {
items: T[];
total: number;
page: number;
PageSize: number;
}
@Injectable({
providedIn: 'root'
})
export class UserService {
private apiUrl = 'https://jsonplaceholder.typicode.com/users';
constructor (private http: HttpClient) { }
//======Get Request ======
// Basic GET - Fetch all users
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl).pipe(
retry(2); //Retry failed request 2 times
tap(users => console.log('Fetched User: ', users.length)),
catchError(this.handleError)
);
}
// GET with Query Parameters
getUserWithId(id: number): Observable<User>{
return this.http.get<User>(`${this.apiUrl}/${id}`).pipe(
tap(user => console.log('Fetched User: ', user.name)),
catchError(this.handleError)
);
}
// Get with Query Paramaters
getUsersWithParams(page: number = 1, limit: number= 5): Observable<user[]>{
const params = new HttpParams()
.set('_page', page.toString())
.set('_limit', limit.toString());
return this.http.get<User[]>(this.apiUrl, { params }).pipe(
catchError(this.toString());
);
}
// Get With Multiple Query Parameters
searchUsers(filters: {name?:string; email?: string}): Observable<User[]>{
let params = new HttpParams();
if(filters.name){
params = params.set('Name', filters.name);
}
if(filters.Eamil){
params = params.set('email', filters.email);
}
return this.http.get<User[]>(this.apiUrl, { params }).pipe(
catchError(this.handleError)
);
}
//Get With Custom Headers
getUserswithHeaders(): Observable<User[]> {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-Custom-Header': 'CustomValue',
'Autherization': 'Bearer token123'
});
return this.http.get<User[]>(this.apiUrl, {headers}).pipe(
catchError(this.handleError);
);
}
// GET with full Response (including headers and status)
getUsersFullResponse(): Observable<any> {
return this.http.get(this.apiUrl, { observe: 'response' }).pipe(
map(response => {
console.log('Status Code:', response.status);
console.log('Status Text:', response.statusText);
console.log('Headers', response.headers.keys());
console.log('Body:', response.body);
}),
catchError(this.handleError)
);
}
// GET as Text (not JSON)
getUsersAsText(): Observable<string> {
return this.http.get(this.apiUrl, { responseType: 'text' }).pipe(
catchError(this.handleError)
);
}
// GET as Blob (for file downloads)
downloadUserReport(): Observable<Blob> {
return this.http.get(`${this.apiUrl}/report`, { responseType: 'blob'}).pipe(
catchError(this.handleError)
);
}
//========== POST REQUEST ==============
// Basic POST - Create new User
createUser(user: User): Observable<User> {
return this.http.post<User>(this.apiUrl, user).pipe(
tap(newUser => console.log('Created user with ID', newUser.id)),
catchError(this.handleError)
);
}
// POST with Headers
createUserWithHeaders(user: User): Observable<User> {
const headers = new HttpHeaders({
'Content-Type':'application/json',
'Autherization': 'Bearer token123'
});
return this.http.post<USer>(this.apiUrl, user, { headers }).pipe(
catchError(this.handleError)
);
}
// POST with full Response
cerateUserFullResponse(user: User): Observable<any> {
return this.http.post(this.apiUrl, user, {observe: 'response'}).pipe(
map(response => {
map(response => {
console.log('Status Code:', response.status);
console.log('Status Text:', response.statusText);
console.log('Headers', response.headers.keys());
console.log('Body:', response.body);
}),
catchError(this.handleError)
})
);
}
// POST FormData (for file upload)
uploadUserwithFile(user: User, file: File): Observable<any>{
const formData = new FormData();
formdata.append('user', JSON.stringify(user));
formdata.append('file', file, file.name);
return this.http.post(`${this.apiUrl}/upload`, formdata).pipe(
catchError(this.handleError)
);
}
//===========PUT REQUEST=============
// PUT - Complete replecment of resource
updateUser(id: number, user: User): Observable<User>{
return this.http.put<User>(`${this.apiUrl}/${id}`, user).pipe(
tap(updatedUser => console.log('Update user', updatedUser)),
catchError(this.handleError)
);
}
// PUT with headers
updateUserWithHeradrs(id: number, user: User): Observable<User> {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'If-Match': 'etag-value' // For optimistic locking
});
return this.http.put<User>(`${this.apiUrl}/${id}`, user, { headers }).pipe(
catchError(this.handleError)
);
}
//===============Patch REQUESTS===============
//PATCH - Partical update
patchUser(id: number, updates: Partial<User>): Observable<User> {
tap( patchedUser => console.log ('Patched user:', patchedUser)).pipe(
catchError(this.handleError)
);
}
// PATCH specific field
updateUserEmail(id: number, email: string): Observable<User> {
return this.http.patch<User>(`${this.apiUrl}/${id}`, {email}).pipe(
catchError(this.handleError)
);
}
//================Delete REQUEST=================
// Basic Delete
deleteUser(id: number): Observable<void> {
return this.http.delete<void>(`${this/apiUrl}/${id}`).pipe(
tap(()=> consloe.log(`Deleted user with ID:`)),
catchError(this.handleError)
);
}
//Delete with Response
deleteUserWithResponse(id: number): Observable<any> {
return this.http.delete(`${this.apiUrl}/${id}`, {observe: 'response'}).pipe(
map( response => {
console.log('Deleted Status:', response.status);
return response;
}),
catchError(this.handleError)
);
}
}
Comments
Post a Comment