Welcome to our deep dive into Angular’s HttpClient! This powerful module enables seamless communication with backend services and APIs. Let’s master it together.
Why HttpClient?
Angular’s HttpClient provides:
- A testable, type-safe way to make HTTP requests
- Observable-based API
- Interceptor support
- Request/response transformation
- Error handling built-in
Setting Up HttpClient
First, import HttpClientModule in your root module:
typescript
// app.module.ts
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule // ← Add this
]
})
export class AppModule { }
Basic HTTP Operations
Here’s how to perform CRUD operations:
1. GET Request (Fetch Data)
typescript
// data.service.ts
getPosts(): Observable<Post[]> {
return this.http.get<Post[]>('https://api.example.com/posts');
}
2. POST Request (Create Data)
typescript
createPost(post: Post): Observable<Post> {
return this.http.post<Post>('https://api.example.com/posts', post);
}
3. PUT/PATCH Request (Update Data)
typescript
updatePost(id: number, post: Post): Observable<Post> {
return this.http.put<Post>(`https://api.example.com/posts/${id}`, post);
// Or for partial updates:
// return this.http.patch<Post>(...)
}
4. DELETE Request (Remove Data)
typescript
deletePost(id: number): Observable<void> {
return this.http.delete<void>(`https://api.example.com/posts/${id}`);
}
Advanced Request Configuration
Customize requests with options:
typescript
getPosts(): Observable<Post[]> {
return this.http.get<Post[]>('https://api.example.com/posts', {
params: new HttpParams().set('limit', '10'), // Query params
headers: new HttpHeaders().set('Authorization', 'Bearer token'),
observe: 'response' // Get full HttpResponse
});
}
Handling Responses
Process responses properly:
typescript
getPosts(): Observable<Post[]> {
return this.http.get<Post[]>('/api/posts').pipe(
tap(response => console.log('Raw response:', response)),
map(response => response.map(post => ({
...post,
createdAt: new Date(post.createdAt)
}))),
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
if (error.status === 0) {
console.error('Client-side or network error:', error.error);
} else {
console.error(`Backend returned code ${error.status}:`, error.error);
}
return throwError(() => new Error('Something went wrong'));
}
Interceptors: Powerful Middleware
Create interceptors for cross-cutting concerns:
typescript
// auth.interceptor.ts
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authToken = localStorage.getItem('auth_token');
if (authToken) {
const authReq = req.clone({
headers: req.headers.set('Authorization', `Bearer ${authToken}`)
});
return next.handle(authReq);
}
return next.handle(req);
}
}
Register interceptors in your module:
typescript
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
Common Interceptor Use Cases
- Authentication: Add auth tokens
- Error Handling: Global error processing
- Caching: Cache responses
- Logging: Track requests
- Mocking: Fake backend for development
Progress Events
Track upload/download progress:
typescript
uploadFile(file: File): Observable<HttpEvent<any>> {
const formData = new FormData();
formData.append('file', file);
return this.http.post('/api/upload', formData, {
reportProgress: true,
observe: 'events'
}).pipe(
filter(event => event.type === HttpEventType.UploadProgress),
map(event => {
if (event.type === HttpEventType.UploadProgress) {
return Math.round(100 * event.loaded / (event.total || 1));
}
return 0;
})
);
}
Best Practices
- Service Layer: Keep HTTP calls in services, not components
- Type Safety: Always type your requests/responses
- Error Handling: Handle errors at service level
- Unsubscribe: Manage subscriptions properly
- Environment Config: Store API URLs in environment files
Hands-On Exercise
Build a complete UserService with:
- Methods for all CRUD operations
- JWT authentication interceptor
- Error handling
- Type-safe interfaces for User model
What’s Next?
In Part 10, we’ll explore Routing & Navigation – how to build single-page application navigation!
