HttpClient and interceptors in Angular
HttpClient
Angular's HttpClient provides a typed HTTP API built on RxJS Observables. It handles JSON serialization, error handling, and request/response transformation.
Basic Usage
typescript
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class ApiService {
private http = inject(HttpClient);
// GET
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users');
}
// GET with params
searchUsers(query: string): Observable<User[]> {
return this.http.get<User[]>('/api/users', {
params: { q: query, limit: '10' }
});
}
// POST
createUser(user: CreateUserDto): Observable<User> {
return this.http.post<User>('/api/users', user);
}
// PUT
updateUser(id: string, data: Partial<User>): Observable<User> {
return this.http.put<User>(\`/api/users/\${id}\`, data);
}
// DELETE
deleteUser(id: string): Observable<void> {
return this.http.delete<void>(\`/api/users/\${id}\`);
}
}Error Handling
typescript
import { catchError, retry, throwError } from 'rxjs';
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users').pipe(
retry(2), // Retry failed requests twice
catchError(error => {
if (error.status === 404) {
return of([]); // Return empty array for 404
}
console.error('API Error:', error.message);
return throwError(() => new Error('Failed to load users'));
})
);
}HTTP Interceptors
Interceptors modify every HTTP request/response — authentication, logging, error handling, etc.
Functional Interceptor (Modern)
typescript
import { HttpInterceptorFn } from '@angular/common/http';
// Auth interceptor — add token to every request
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService);
const token = authService.getToken();
if (token) {
const cloned = req.clone({
setHeaders: { Authorization: \`Bearer \${token}\` }
});
return next(cloned);
}
return next(req);
};
// Logging interceptor
export const loggingInterceptor: HttpInterceptorFn = (req, next) => {
const started = Date.now();
return next(req).pipe(
tap(event => {
if (event instanceof HttpResponse) {
console.log(\`\${req.method} \${req.url} — \${Date.now() - started}ms\`);
}
})
);
};
// Error interceptor
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
return next(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
inject(Router).navigate(['/login']);
}
return throwError(() => error);
})
);
};Register Interceptors
typescript
// main.ts
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(
withInterceptors([
authInterceptor,
loggingInterceptor,
errorInterceptor,
])
),
],
});Common Interceptor Use Cases
| Use Case | What it does |
|---|---|
| Authentication | Add Bearer token to requests |
| Error handling | Global error toast, redirect on 401 |
| Loading indicator | Show/hide spinner on requests |
| Caching | Cache GET responses |
| Retry | Retry failed requests |
| Logging | Log request/response timing |
Important:
HttpClient returns Observables for all HTTP methods — use pipe() with RxJS operators for error handling and transformation. Interceptors are middleware for HTTP requests — use them for auth tokens, error handling, and logging. Prefer functional interceptors (HttpInterceptorFn) over class-based ones.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.