Angular Interceptors

One of the great things that the new Javascript frameworks have introduced are practices that would normally be found on the server. Personally I am holding out hope for WASM and Blazor to save us from Javascript once and for all. That doesn’t mean we can’t improve our quality of life though by using what is currently on offer. Angular and its contemporary Javascript framework counterparts are light years ahead of JQuery. JQuery served its purpose for its time, but it’s time to move on, and building green field applications with it is a non-starter for me.

Aspect Oriented Programming

I want to start off with a very brief introduction to Aspect Oriented Programming. If you haven’t used it before, or have never heard of it, you’re missing out on one of the most powerful tools in your toolbox. I’m going to give you a very bare bones explanation in plain speak. If you want something more in depth and technical then there are other resources out there. AOP revolves around the creation and usage of what are called “Aspects”. An aspect is really nothing more than a piece of code that gets called at predefined execution points. As an example, two of the most common you will see are OnActionExecuted and OnActionExecuting in the .NET world. If you decorate a method with a filter in .NET Core, you are using a form of AOP. Your filter code will then execute on every method decorated by it at the predefined execution point.

That’s all AOP really is in a nutshell. On the .NET platform there are numerous implementations of AOP including filters, middleware, IoC container interceptors, and the nuclear option of them all PostSharp. If you want a non-trivial example of AOP in action with a real world scenario, then check out my blog post ASP.NET Core Request Post Processing. Any time you find yourself doing the same thing, or a similar set of actions, over and over then it is usually a candidate for AOP. Personally, I don’t want to call the logger at the beginning of every method call, or validation, or check for authorization. These are all actions that can be performed by an aspect running a snippet of code.

Request Interception in Angular

Which finally brings us to the point of this blog post. In JQuery you are probably familiar with the typical AJAX call set up where you make a call to the server, it returns you a result, and you handle it in the success or error promise. Then you call whatever you need to do from there. Often times this involved checking for validation or exception messages and then displaying it to the user. Even if you are using a service of some sort to do all this for you, you still have to call the methods of the service. What if we could handle this automatically though with out ever having to do anything?

Observe the below request interceptor:


import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from "rxjs";
import { v4 as uuid } from 'uuid';

@Injectable()
export class HttpRequestInterceptor implements HttpInterceptor {
    constructor() {

    }
    intercept(req: HttpRequest, next: HttpHandler): Observable<HttpEvent> {
        req = req.clone({
            setHeaders: {
                Authorization: `Bearer ${localStorage.getItem('accessToken')}`,
                'CorrelationId': uuid()
            }
        });

        return next.handle(req);
    }
}

What this code is doing is it automatically creates the correlation id that is used for logging and it sets the authorization headers with the access token for the user. Every request will have this piece of code run on it before it is passed off down the rest of the pipeline. Before we can use this, we need to register it so that Angular will wire it up for us. You’ll want to do this in your module that wires everything up. In my case I am using the visual studio template for Angular 5 which is done in a file named “app.shared.module.ts”. The following is an abbreviated version of my file:


import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
providers: [
{
            provide: HTTP_INTERCEPTORS,
            useClass: Interceptors.HttpRequestInterceptor,
            multi: true
        },
        {
            provide: HTTP_INTERCEPTORS,
            useClass: Interceptors.HttpResponseInterceptor,
            multi: true
        }
]
})

This is all that is needed to wire up your interceptor. The request interceptor is pretty simple, but you’ll notice I’m also using a response interceptor. Lets take things a step further and look at some of the usage scenarios when handling responses with interceptors.

Response Interception in Angular

We’re going to follow the same basic set up as our request interceptor. It’s also going to get wired up in the same way given the code above. The response interceptor is going to demonstrate some of the more powerful implementations that AOP can bring to your code. Observe the following:


import { Injectable, Inject } from "@angular/core";
import { HttpInterceptor, HttpErrorResponse, HttpResponse, HttpEvent, HttpRequest, HttpHandler } from "@angular/common/http";
import { Observable } from "rxjs";
import { AuthenticationService } from "../services/auth.service";
import { AppSharedService } from "../services/app.shared.service";
import { GrowlMessageSeverity, GrowlMessageSummary } from "../models/index";

@Injectable()
export class HttpResponseInterceptor implements HttpInterceptor {

    constructor(private authService: AuthenticationService, private appSharedService: AppSharedService, @Inject('IDENTITY_URL') private identityUrl: string) { }

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

        return next.handle(req).do((event: HttpEvent) => {
            if (event instanceof HttpResponse) {
            }
        }, (err: any) => {
            if (err instanceof HttpErrorResponse) {
                if (err.status === 401) {
                    this.appSharedService.onLoading.emit(false);
                    this.authService.removeUser();
                    window.location.href = this.identityUrl;
                }
                if (err.status === 400) {
                    this.appSharedService.onLoading.emit(false);
                    this.appSharedService.onValidationError.emit(err.error);
                }
                if (err.status === 500) {
                    this.appSharedService.onLoading.emit(false);
                    this.appSharedService.onSendGrowlMessage.emit({ severity: GrowlMessageSeverity.error, summary: GrowlMessageSummary.error, detail: 'An error has occurred. Please contact support for assistance if the issue persists.' });
                }
                if (err.status === 0) {
                    this.appSharedService.onLoading.emit(false);
                    this.appSharedService.onSendGrowlMessage.emit({ severity: GrowlMessageSeverity.error, summary: GrowlMessageSummary.error, detail: 'An error has occurred. Please contact support for assistance if the issue persists.' });
                }
            }
        });
    }
}

This is actual code that I use in a CRM I built recently. What this is doing is it is checking the response HTTP status code and then handling it appropriately. In my .NET Core API I am returning a 400 BadRequestObjectResult when there is a validation error. On the Angular side every time 400 is return I then stop the loading bar and pass off the error messages to the shared service that displays messages for the entire system. This few lines of code handles all validation messages from the server everywhere and on every response. Likewise for 401 and 500. This is just one example though of what is possible. Any time you find yourself doing the same task over and over again, or a set of predefined steps that must be executed based on a criteria, then it is a candidate for AOP. The server side has had this capability for years, and finally we can now do it with relative ease in the Javascript world. Use your new found power wisely.

Thanks for reading.

Sean Leitzinger

Solutions Architect at Edgeside Solutions
.NET and C# aficionado with an interest in architecture, patterns, practices, and more. Microsoft fanatic.

Latest posts by Sean Leitzinger (see all)

Leave a Reply

Your email address will not be published. Required fields are marked *