0 day streak
javascript / expert
Snippet

Recoverable Error Boundaries with RxJS catchError Chains

Demonstrates a layered error-recovery strategy for an Angular service: bounded retries for transient network issues, a timeout guard against hanging requests, and a custom error class that distinguishes recoverable server failures (silently substituted with defaults) from unrecoverable ones (rethrown for the caller to handle). This avoids the common anti-pattern of either swallowing every error or crashing the component on any failure.

snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError, of } from 'rxjs';
import { catchError, retry, timeout } from 'rxjs/operators';
class RecoverableApiError extends Error {
constructor(message: string, public readonly statusCode: number, public readonly fallbackUsed: boolean) {
super(message);
this.name = 'RecoverableApiError';
}
}
@Injectable({ providedIn: 'root' })
export class ResilientConfigService {
constructor(private http: HttpClient) {}
loadConfig(): Observable<Record<string, unknown>> {
return this.http.get<Record<string, unknown>>('/api/config').pipe(
timeout(3000),
retry({ count: 2, delay: 500 }),
catchError((err: HttpErrorResponse) => {
if (err.status >= 500) {
console.error(new RecoverableApiError('Server unavailable, using defaults', err.status, true));
return of({ theme: 'default', locale: 'en' });
}
return throwError(() => new RecoverableApiError('Config fetch failed', err.status, false));
}),
);
}
}
angular
Breakdown
1
class RecoverableApiError extends Error
A custom error subclass carrying structured metadata (statusCode, fallbackUsed) so downstream handlers can branch on error semantics rather than parsing message strings.
2
retry({ count: 2, delay: 500 })
Limits retries to two attempts with a fixed delay, preventing an unbounded retry storm against a struggling backend.
3
return of({ theme: 'default', locale: 'en' });
Silently degrades to safe defaults for 5xx errors instead of failing the whole app shell.