Let’s have an Angular application that is a client to an API.
The API, of course, may return error responses.
Let’s handle the errors in a consistent way.
Create an ErrorInterceptor⌗ Use an Interceptor for inspecting the HTTP responses.
error-interceptor.ts
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpErrorResponse
} from '@angular/common/http';
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(private myErrorHandlingService errorHandler) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
return next.handle(req).pipe(
catchError((err: HttpErrorResponse) => {
myErrorHandlingService.handle(err); 1
return throwError(err); 2
}
)
);
}
}
Register the interceptor in the app.module.ts
app.module.ts
import {ErrorInterceptor} from 'path-to-my-interceptor/error-interceptor';
@Module({
//...
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: ErrorInterceptor,
multi: true
}],
// ...
})
export class AppModule {}
Create an Error Component⌗ Create an error component (ng g c error/error.component ).
error.component.html
< div >
< h1 mat-dialog-title > An error has occured</ h1 >
< div mat-dialog-content >
< p class = "mat-body-1" > {{ data.message }}< p >
</ div >
< div mat-dialog-actions >
< button mat-button mat-dialog-close > OK</ button >
</ div >
</ div >
error.component.ts
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material';
@Component({
templateUrl: './error.component.html'
})
export class ErrorComponent {
constructor(@Inject(MAT_DIALOG_DATA) public data: {message: string}) {} 1
}
This allows the injection when spawning the Material Dialog
Register the ErrorComponent for dynamic creation.
app.module.ts
// ...
import { ErrorComponent } from 'path-to/error.component.ts'
@NgModule({
// ...
entryComponents: [ErrorComponent]
})
Display the Dialog⌗ Import the MatDialogModule .
error-handling.service.ts
@Injectable()
export class ErrorHandlingService {
constructor(private dialog: MatDialog){}
public handle(error: any) {
const message = error.message || 'Unknown error';
this.dialog.open(ErrorComponent, {
data: { message: message }
});
}
}
Summary⌗ This was a simple howto for creating an error handling interceptor and displaying an error in a dialog.
There is still a lot of work to do to finalize the component,
for example some styling would be nice.
Also, a modal dialog might be a bit annoying, maybe a toast message might be more appropriate.
Anyway, I find this pattern quite nice since it centralizes and modularizes the error handling.
It’s definitely better than having a special 'catch' callback in every API call like I have encountered at my last work project.