Reactivity
HttpClient, interceptors & error handling
Typed API calls, interceptor pipeline, retries and centralised error handling.
HttpClient returns cold observables of typed responses. Functional interceptors (HttpInterceptorFn) form a pipeline around every request — the idiomatic home for auth headers, correlation IDs, logging, and global error handling.
Interceptors are the mailroom: every outgoing parcel gets stamped and logged, and every damaged return parcel is handled before it reaches your desk.
Key concepts
1
Robust APIs layer retry (with backoff), timeout, and catchError to translate transport errors into domain results, so components handle a clean success/empty/error state rather than raw HTTP failures.
retrytimeoutcatchError
2
A refresh-token interceptor typically catches 401s, refreshes once, and retries queued requests — a classic senior implementation exercise.
refresh-token interceptor
3
Pitfall: swallowing errors in catchError and returning of(null) hides real failures; log and surface them. Best practice: keep interceptors pure and ordered deliberately — the order they are registered is the order they wrap the request.
Pitfall:Best practice:catchErrorof(null)
typescript
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = inject(AuthStore).token();
const authed = token ? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }) : req;
return next(authed).pipe(
retry({ count: 2, delay: 500 }),
catchError((e: HttpErrorResponse) => {
inject(Toast).error(e.status === 0 ? 'Network down' : e.message);
return throwError(() => e);
}),
);
};