3
votes

Aim: to have a global error handler for server errors and app errors (produced in Typescript code).

How: providing a custom ErrorHandler from a lib project inside the same workspace. This is my lib structure:

@common/error-handling lib

I have following http-interceptor (http-error.interceptor.ts)

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {

  constructor(@Inject(LOGGER_SERVICE) private logger: ILoggerService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req)
    .pipe(
        catchError( (error: HttpErrorResponse) => {
          console.log('error');

          return throwError(error);
        })
    );
  }
}

The following custom global error handler (errors-handler.ts):

import { ErrorHandler, Injectable } from '@angular/core';

@Injectable()
export class ErrorsHandler implements ErrorHandler {

    handleError(error: any): void {
        console.log('hi!');
    }

}

And this is the error-handling.module.ts

import { NgModule, ErrorHandler } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpErrorInterceptor } from './http-error.interceptor';
import { ErrorsHandler } from './errors-handler';

    @NgModule({
      declarations: [],
      imports: [
      ],
      exports: [],
      providers: [
        {provide: ErrorHandler, useClass: ErrorsHandler},
        {provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true}
      ]
    })
    export class ErrorHandlingModule { }

In my public_api.ts file I only export the module

/*
 * Public API Surface of error-handling
 */

export * from './lib/error-handling.module';

In the same workspace I have an app (the default app provided by Angular CLI, it is not inside projects folder). In my app.module.ts I have imported the ErrorHandlingModule :

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { ErrorHandlingModule } from '@common/error-handling';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { CoreModule } from './core/core.module';



@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    CoreModule,

    ErrorHandlingModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

I have already built my @common/error-handling lib. I also have a fake api with json-server in which I have defined a "categories" end point. I call that service on app.component.ts in the onInit method, producing a 404 http error response by calling to the endpoint "categorie" (without "s"). I have the following in the console when I serve my app:

Error shown in console, but not catched by global error handler

The 404 error is there, I can also see the "error" log from http-error.interceptor.ts, but I cannot see the "hi!" log from my custom ErrorHandler.

The global error handler is working when I throw an error from app.component.ts after calling the fake api endpoint. Somehow, the line

return throwError(error);

in http-error.interceptor.ts is not reaching my global error handler.

Is it something related to zone.js? The error is thrown there and not bubbled up to the rest of the app. I am not so familiar with zone.js.

Any other thoughts?

Thanks in advance!

Best, Max.

2
When I throw error from Interceptor ErrorHandler can not catch it why? - Muhammed Ozdogan
@MuhammedOzdogan I do not understand your question. Could you please reformulate it? - Max Tomasello
You have this statement : "return throwError(error);" in HttpErrorInterceptor class. Should "ErrorsHandler" catch that? - Muhammed Ozdogan

2 Answers

3
votes
export class ErrorHandlingModule { 
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: ErrorHandlingModule,
      providers: [
        {provide: ErrorHandler, useClass: ErrorsHandler},
        {provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true} ]
    };
}

and then in the AppModule import with ErrorHandlingModule.forRoot()

For extra info - https://angular.io/api/router/RouterModule#forRoot

0
votes

If your observable takes a callback for the error, the throwError operator will be returned to the observer and will not be picked up by the global error interceptor.

Just comment the catchError block in subscribe

getWorkData(id: string): void {
this.userDataService.getWorkData(id).subscribe(
  (response) => {
    this.Id = response.Id;
    this.localStorage.setItem('WorkData', response);
  }
  // (err) => {
  //   //this.monitoringService.logException(err);
  // },
);
}