Handling HTTP Errors
HTTP errors arrive in the error channel of the Observable. catchError lets you intercept and recover from failures.
Basic Error Handling
import { catchError, throwError } from 'rxjs';
this.http.get<User[]>('/api/users').pipe(
catchError(error => {
console.error('Request failed:', error.message);
return throwError(() => new Error('Failed to load users'));
})
).subscribe({
next: users => console.log('Users:', users),
error: err => console.error('Error:', err.message),
});
HttpErrorResponse
import { HttpErrorResponse } from '@angular/common/http';
catchError((error: HttpErrorResponse) => {
if (error.error instanceof ErrorEvent) {
// Client-side or network error
console.error('Client error:', error.error.message);
} else {
// Server-side error
console.error(`Server error: ${error.status} ${error.statusText}`);
console.error('Error body:', error.error);
}
return throwError(() => error);
})
Common HTTP Status Codes
| Status | Meaning | Handling |
|---|---|---|
| 400 | Bad Request | Show validation errors |
| 401 | Unauthorized | Redirect to login |
| 403 | Forbidden | Show access denied |
| 404 | Not Found | Show not found message |
| 500 | Server Error | Show generic error, retry |
| 503 | Service Unavailable | Show maintenance message |
Fallback Values
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users').pipe(
catchError(() => of([])) // Return empty array on error
);
}
Retry Logic
import { retry, catchError } from 'rxjs';
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users').pipe(
retry(2), // Retry up to 2 times before failing
catchError(error => {
console.error('Failed after retries:', error);
return of([]);
})
);
}
Status-Specific Error Handling
Different HTTP status codes require different handling strategies.
Status-Specific Handler
private handleError(error: HttpErrorResponse): Observable<never> {
if (error.status === 401) {
// Redirect to login
this.router.navigate(['/login']);
return throwError(() => new Error('Session expired'));
}
if (error.status === 403) {
this.notification.show('Access denied');
return throwError(() => new Error('Forbidden'));
}
if (error.status === 404) {
this.notification.show('Resource not found');
return throwError(() => new Error('Not found'));
}
if (error.status >= 500) {
this.notification.show('Server error. Please try again.');
return throwError(() => new Error('Server error'));
}
return throwError(() => error);
}
Using in a Service
@Injectable({ providedIn: 'root' })
export class UserService {
private http = inject(HttpClient);
private router = inject(Router);
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users').pipe(
catchError(error => this.handleError(error))
);
}
private handleError(error: HttpErrorResponse): Observable<never> {
// Status-specific handling
return throwError(() => error);
}
}
Global Error Interceptor
For centralized error handling, use an HTTP interceptor (covered in the next topic).
Quiz
1. What RxJS operator intercepts HTTP errors?
2. What does HttpErrorResponse expose?
3. How do you retry a failed HTTP request?
Flashcards
Question
How do you handle HTTP errors?
Click to reveal answer
Answer
catchError operator — intercepts errors, allows fallback values or re-throwing.
Question
What does HttpErrorResponse expose?
Click to reveal answer
Answer
status, statusText, and the parsed error body from the server.
Question
How do you retry failed requests?
Click to reveal answer
Answer
retry(n) operator — resubscribes up to n times on error.
Revision Notes
Key Takeaways
- 1. catchError intercepts HTTP errors
- 2. HttpErrorResponse exposes status, statusText, and body
- 3. retry(n) resubscribes on failure
- 4. Use fallback values for graceful degradation
Interview Tips
- • Explain the error channel in Observables
- • Be ready to describe status-specific handling
- • Mention interceptors for centralized error handling
Cheat Sheet
HTTP Error Handling Cheat Sheet
Basic handling:
catchError((error: HttpErrorResponse) => {
console.error(error.status, error.statusText);
return throwError(() => error);
})
Fallback value:
catchError(() => of([]))
Retry:
retry(2)
Status codes:
- 401: redirect to login
- 403: access denied
- 404: not found
- 500+: server error