7

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.

3
  • When I throw error from Interceptor ErrorHandler can not catch it why? Commented Jun 27, 2019 at 8:54
  • @MuhammedOzdogan I do not understand your question. Could you please reformulate it? Commented Jun 29, 2019 at 1:49
  • You have this statement : "return throwError(error);" in HttpErrorInterceptor class. Should "ErrorsHandler" catch that? Commented Jun 29, 2019 at 18:00

3 Answers 3

4
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

Sign up to request clarification or add additional context in comments.

1 Comment

thanks for your answer. The problem was really stupid. I had a class that used as a base service (all services inherited from this base service), and there I had a catchError to return default values on error. Since this was the last catch of the chain, I was not hitting the global error handler. Sorry for wasting your time and thanks for answering again!
1

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);
  // },
);
}

Comments

1

I found @avramz's answer helpful. I just want to provide a more complete example of what I did.

Bootstrap code

providers: [...,
  {
    provide: HTTP_INTERCEPTORS,
    useClass: HttpErrorInterceptorService,
    multi: true,
  },
]

Service code

@Injectable({ providedIn: 'root' })
export class HttpErrorInterceptorService implements HttpInterceptor {

  constructor(
    readonly matSnackbar: MatSnackBar,
  ) {
  }
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
      catchError(e => {
        this.matSnackbar.showErrorUnexpected(`Something unexpected happened (${e.status})`);
        return throwError(() => e);
      }),
    );
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.