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
}
  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.