From f12e69b5dfbfb80735f8e35f648b566d03178c3d Mon Sep 17 00:00:00 2001 From: Spencer Ofwiti Date: Sun, 21 Mar 2021 16:11:05 +0300 Subject: [PATCH] Move error handler to error interceptor. --- src/app/_helpers/global-error-handler.ts | 16 +++++-- src/app/_interceptors/error.interceptor.ts | 55 ++++++++++++++++------ src/app/_services/auth.service.ts | 22 ++------- src/app/app.module.ts | 2 +- 4 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/app/_helpers/global-error-handler.ts b/src/app/_helpers/global-error-handler.ts index 5d440f9..e524bd0 100644 --- a/src/app/_helpers/global-error-handler.ts +++ b/src/app/_helpers/global-error-handler.ts @@ -1,12 +1,16 @@ import {ErrorHandler, Injectable} from '@angular/core'; import {LoggingService} from '@app/_services/logging.service'; import {HttpErrorResponse} from '@angular/common/http'; +import {Router} from '@angular/router'; @Injectable() export class GlobalErrorHandler extends ErrorHandler { private sentencesForWarningLogging: string[] = []; - constructor(private loggingService: LoggingService) { + constructor( + private loggingService: LoggingService, + private router: Router + ) { super(); } @@ -31,15 +35,17 @@ export class GlobalErrorHandler extends ErrorHandler { } logError(error: any): void { + const route = this.router.url; if (error instanceof HttpErrorResponse) { this.loggingService.sendErrorLevelMessage( - `There was an HTTP error. ${error.message}, Status code: ${(error as HttpErrorResponse).status}`, this, {error}); + `There was an HTTP error on route ${route}.\n${error.message}.\nStatus code: ${(error as HttpErrorResponse).status}`, + this, {error}); } else if (error instanceof TypeError) { - this.loggingService.sendErrorLevelMessage(`There was a Type error. ${error.message}`, this, {error}); + this.loggingService.sendErrorLevelMessage(`There was a Type error on route ${route}.\n${error.message}`, this, {error}); } else if (error instanceof Error) { - this.loggingService.sendErrorLevelMessage(`There was a general error. ${error.message}`, this, {error}); + this.loggingService.sendErrorLevelMessage(`There was a general error on route ${route}.\n${error.message}`, this, {error}); } else { - this.loggingService.sendErrorLevelMessage('Nobody threw an error but something happened!', this, {error}); + this.loggingService.sendErrorLevelMessage(`Nobody threw an error but something happened on route ${route}!`, this, {error}); } } diff --git a/src/app/_interceptors/error.interceptor.ts b/src/app/_interceptors/error.interceptor.ts index adf16bf..a0fe704 100644 --- a/src/app/_interceptors/error.interceptor.ts +++ b/src/app/_interceptors/error.interceptor.ts @@ -6,26 +6,51 @@ import { HttpInterceptor, HttpErrorResponse } from '@angular/common/http'; import {Observable, throwError} from 'rxjs'; -import {catchError} from 'rxjs/operators'; -import {ErrorDialogService} from '@app/_services'; +import {catchError, retry} from 'rxjs/operators'; +import {ErrorDialogService, LoggingService} from '@app/_services'; +import {Router} from '@angular/router'; @Injectable() export class ErrorInterceptor implements HttpInterceptor { - constructor(private errorDialogService: ErrorDialogService) {} + constructor( + private errorDialogService: ErrorDialogService, + private loggingService: LoggingService, + private router: Router + ) {} intercept(request: HttpRequest, next: HttpHandler): Observable> { - return next.handle(request).pipe(catchError((err: HttpErrorResponse) => { - if (isDevMode()) { - this.errorDialogService.openDialog({ - message: err.error.message || err.statusText || 'Unknown Error', - status: err.status || 0 - }); - } - if ([401, 403].indexOf(err.status) !== -1) { - location.reload(true); - } - return throwError(err); - })); + return next.handle(request).pipe( + retry(1), + catchError((err: HttpErrorResponse) => { + let errorMessage; + if (err.error instanceof ErrorEvent) { + // A client-side or network error occurred. Handle it accordingly. + errorMessage = `An error occurred: ${err.error.message}`; + this.loggingService.sendErrorLevelMessage(errorMessage, this, {error: err}); + } else { + // The backend returned an unsuccessful response code. + // The response body may contain clues as to what went wrong. + errorMessage = `Backend returned code ${err.status}, body was: ${JSON.stringify(err.error)}`; + this.loggingService.sendErrorLevelMessage(errorMessage, this, {error: err}); + } + if (isDevMode()) { + this.errorDialogService.openDialog({ + message: errorMessage || err.error.message || err.statusText || 'Unknown Error', + status: err.status || 0 + }); + } + switch (err.status) { + case 401: // unauthorized + this.router.navigateByUrl('/auth').then(); + break; + case 403: // forbidden + location.reload(true); + break; + } + // Return an observable with a user-facing error message. + return throwError(err); + }) + ); } } diff --git a/src/app/_services/auth.service.ts b/src/app/_services/auth.service.ts index 80a9eb8..72f5686 100644 --- a/src/app/_services/auth.service.ts +++ b/src/app/_services/auth.service.ts @@ -6,8 +6,8 @@ import {LoggingService} from '@app/_services/logging.service'; import {MutableKeyStore, MutablePgpKeyStore} from '@app/_pgp'; import {ErrorDialogService} from '@app/_services/error-dialog.service'; import {tap} from 'rxjs/operators'; -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import {Observable, throwError} from 'rxjs'; +import { HttpClient } from '@angular/common/http'; +import {Observable } from 'rxjs'; @Injectable({ providedIn: 'root' @@ -154,7 +154,7 @@ export class AuthService { return this.httpClient.get(`${environment.publicKeysUrl}`, {responseType: 'text'}) .pipe(tap( data => { }, - error => { this.handleError(error, 'Unable to load trusted public keys.'); } + error => { this.loggingService.sendErrorLevelMessage('Unable to load trusted public keys.', this, {error}); } )); } @@ -163,20 +163,4 @@ export class AuthService { await this.mutableKeyStore.importPrivateKey(this.privateKey); } } - - // TODO this is from the docs and for reference. Move it somewhere better. - private handleError(error: HttpErrorResponse, customMessage: string): Observable { - if (error.error instanceof ErrorEvent) { - // A client-side or network error occurred. Handle it accordingly. - console.error('An error occurred:', error.error.message); - } else { - // The backend returned an unsuccessful response code. - // The response body may contain clues as to what went wrong. - console.error( - `Backend returned code ${error.status}, ` + - `body was: ${JSON.stringify(error.error)}`); - } - // Return an observable with a user-facing error message. - return throwError(customMessage); - } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4be5742..45b735b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -44,7 +44,7 @@ import {MutablePgpKeyStore} from '@app/_pgp'; GlobalErrorHandler, { provide: ErrorHandler, useClass: GlobalErrorHandler }, { provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true }, - // { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }, + { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }, // { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }, ], bootstrap: [AppComponent]