gyc
gyc

Reputation: 4360

Handling error with rxjs not compatible with interceptors

Based on this question Angular intercepting http errors that is resolved, I'm facing a huge philosophical issue.

All my services look like this:

public getSomething(): Observable<Something> {
    return this.http
        .get<Something>(url)
        .pipe(
            map(res => res.data),
            catchError((e): Observable<any> => of(e))
        );
}

If my authentication token is invalid / expired, the service catches the error. I can call log out right there.

However, if I have a lot of services, I have to repeat this process that many times. Thus I need to configure an interceptor or a custom error handler.

Both are not triggered if I keep catchError in the services.

If I choose to stay DRY, I need to remove catchError. If I remove catchError, rxjs becomes practically useless (finalize, retry...etc.)

If I choose to keep catchError, I need to modify all of them to call some kind of global error handling function to stay somewhat DRY. But then I'm not using Angular like I should.

How do I handle this situation?

EDIT: https://stackblitz.com/edit/angular-m2jc9n

There's the ErrorHandler active, the Interceptor is commented in app.module. If you remove catchError from the service, the ErrorHandler is triggered, otherwise catchError takes precedence.

Upvotes: 0

Views: 270

Answers (1)

Wandrille
Wandrille

Reputation: 6821

If you want to have a shared interceptor, you have in angular the HTTP_INTERCEPTOR:

in your module.ts

@NgModule({
  declarations: [
   ...
  ],
  imports: [
   ...
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: LoginInterceptor,
      multi: true
    }
  ]
})

And the service LoginInterceptor:

@Injectable()
export class LoginInterceptor implements HttpInterceptor {

  constructor() {
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    return next.handle(request).pipe(
      tap(() => {
        }, (err: any) => {
          if (err instanceof HttpErrorResponse) {
            // DO here what you want
            // this.router.navigate(['login']);
          }
        }
      )
    );
  }
}

An alternative will be to use a guard on the top of your route.

Upvotes: 1

Related Questions