Resilience in Communication: HTTP Error Handling in Angular

Master the art of handling HTTP failures in Angular to build robust, user-friendly applications that never crash unexpectedly.

📡

Welcome! Let's see what happens when an Angular HTTP request goes wrong and how we can fix it.

/* An HTTP request is sent... */

The Unstable Request

In a perfect world, every HTTP request gets a successful response. In reality, networks fail, servers crash, and requests are invalid. An unhandled error can crash your application, leading to a poor user experience. Robust applications must anticipate and manage these failures gracefully.

Intercepting with `catchError`

Angular's HttpClient returns an RxJS Observable. We can use the .pipe() method on this observable to chain operators. The most important for error handling is catchError, which intercepts an error, allowing you to process it without crashing the stream.

Diagnosing with `HttpErrorResponse`

The error caught by catchError is an HttpErrorResponse object. This object contains vital information. You can check error.status (e.g., 404, 500) to understand the failure type and distinguish between a client-side network error and a server-side API error.

Propagating with `throwError`

After logging or handling an error, you should usually re-throw it using the RxJS throwError function. This ensures that the component subscribing to the service knows the request failed and can update the UI accordingly (e.g., by showing an error message instead of a loading spinner).

Practice Zone


Interactive Test 1: Match the Operators

Drag the RxJS function to its correct description.

Arrastra en el orden correspondiente.


Arrastra las opciones:

catchError
throwError

Completa el código:

Intercepts an error in an Observable stream______
Creates a new Observable that emits an error______
Unlock with Premium

Interactive Test 2: Build the Handler

Rellena los huecos en cada casilla.

import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { throwError, Observable } from 'rxjs';
import {  } from 'rxjs/operators';

// ... service definition
getData(): Observable<any> {
  return this.http.get('/api/data').pipe(
    (this.handleError)
  );
}

private handleError(error: HttpErrorResponse) {
  // Logic to handle client or server error
  return ('Something went wrong.');
}
Unlock with Premium

Practice Example: Code Editor

In a service, create a method that fetches data from a fake API endpoint (`/api/users`) and includes full `catchError` and `throwError` logic.

* Write the code below. Correct characters will be shown in green and incorrect ones in red.

import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class UserService { constructor(private http: HttpClient) {} getUsers(): Observable<any> { return this.http.get('/api/users').pipe( catchError(this.handleError) ); } private handleError(error: HttpErrorResponse) { if (error.status === 0) { console.error('A client-side or network error occurred:', error.error); } else { console.error(`Backend returned code ${error.status}, body was: `, error.error); } return throwError(() => new Error('Something bad happened; please try again later.')); } }
Unlock with Premium

Knowledge Check

Which RxJS operator is essential for intercepting errors in an HTTP request stream?


Unlock with Premium

Advanced Error Handling Patterns

Beyond a single service, Angular provides powerful, application-wide patterns for managing HTTP errors efficiently.


1. Centralized Handling with HttpInterceptor

An HttpInterceptor allows you to intercept *every* single HTTP request and response. This is the perfect place to put centralized error handling logic, so you don't have to repeat it in every service.

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler) {
    return next.handle(req).pipe(
      catchError((error: HttpErrorResponse) => {
        // Global error logic here
        return throwError(() => error);
      })
    );
  }
}

2. Automatic Retries with the `retry` Operator

For temporary network issues or transient server errors (like a 503), you can automatically retry a failed request. The retry operator can be added to the pipe before catchError.

// In a service method
return this.http.get('/api/data').pipe(
  retry(2), // Retries up to 2 times
  catchError(this.handleError)
);
📡➡️❌➡️🔁➡️✅

3. Showing User-Friendly Messages

In your component, the `error` callback of the `subscribe` method is where you handle the UI. You can set a property to display an error message to the user, providing a much better experience than a broken page.

this.dataService.getData().subscribe({
  next: (data) => { /* ... */ },
  error: (err) => { this.errorMessage = 'Could not load data.'; }
});
Could not load data.

Practical Takeaway: Combining service-level handlers, global interceptors, and component-level UI feedback creates a truly resilient and professional Angular application.

Angular HTTP Glossary

HttpClient
Angular's built-in service for making HTTP requests. It returns Observables from the RxJS library.
Observable
A stream of data that can be subscribed to. HTTP requests produce an observable that emits a single value (the response) or an error.
pipe()
A method on Observables that allows you to chain together multiple RxJS operators to process the data in the stream.
catchError
An RxJS operator used inside .pipe() to intercept any errors that occur in the observable stream.
HttpErrorResponse
An object passed to the catchError handler that contains detailed information about a failed HTTP request, including the status code and error body.
throwError
An RxJS function that creates a new observable that immediately emits an error. It's used to propagate an error down the stream to the subscriber.