angularangular-http-interceptorsangular-errorhandler

Angular ErrorHandler and HttpErrorResponse


Today I have decided to look more into some centralized error reporting for my Angular application. I used great article on Medium by Michael Karén (https://medium.com/angular-in-depth/expecting-the-unexpected-best-practices-for-error-handling-in-angular-21c3662ef9e4) explaining how to handle both client-side and server-side problems and log them.

In my sample project, I have a really simple interceptor:

export class HttpInterceptor implements NgHttpInterceptor {
  constructor(
    private auth : AuthService
  ) { }
  intercept(request : HttpRequest<any>, next : HttpHandler) : Observable<HttpEvent<any>> {
    return next.handle(request)
      .pipe(
        retry(1),
        catchError((error : HttpErrorResponse) => {
          return throwError(error);
        })
      );
  }
}

And very simple ErrorHandler:

@Injectable()
export class AppErrorHandler implements ErrorHandler {
  constructor(
    private readonly injector : Injector
  ) { }
  handleError(error : Error | HttpErrorResponse) {
    /** injectables */
    const errorService = this.injector.get(ErrorService);
    const loggingService = this.injector.get(LoggingService);
    /** initialize empty variables */
    let message : string;
    let stackTrace : string;
    if (error instanceof HttpErrorResponse) {
      console.log('server');
    } else {
      console.log('client');
    }
  }
}

Yes, so far it is not really logging but that's not an issue. What I noticed, however, is that when using Angular's HttpClient and either 1) using toPromise() method rather than subscribing, or 2) subscribing to error on response, the error handler says that error instanceof HttpErrorResponse is false. So..

This will log 'server' correctly:

this.httpClient.get('foo').subscribe()

This will log 'client' incorrectly:

this.httpClient.get('foo').subscribe(
  data => console.log,
  error => console.error
)

This will also log 'client' incorrectly:

await this.httpClient.get('foo').toPromise()

As I am totally failing to understand what exactly is happening here and why is it an issue, would somebody please help me with correct error reporting of HTTP errors? I was thinking about logging those errors in HttpInterceptor, however when throwing them, the ErrorHandler would log them again as client errors.

Why do I use callback The use of callback is mostly because all these calls are in respective services. For example, user service fetches data from an endpoint, does something with the data and then resolves a promise (or finishes observer, whatever really)

Edit:

I have created a StackBlitz sample illustrating the problem: https://stackblitz.com/edit/angular-ivy-gjtxk2


Solution

  • I have checked the sample of your StackBlitz. If you are facing problem in handling Error in HTTP-Broken 2 then modify your code for catching the error and throw it to GlobalHandler -

      httpBroken2() {
        this.httpClient.get(this.randomUrl()).pipe(catchError((errors: HttpErrorResponse) => {
          // anything you want to do (i.e. modify error)
          return throwError(errors);
        })).subscribe(
          (data) => {
            alert(data);
          }
        )
      }