Community Post

JIT vs AOT in Angular2 and how to use it

Kashyap Mukkamala

What is an Interceptor?

Interceptor, especially in AngularJS world, became widely popular with Angular 1.x, where you can intercept and change a request before it is fired without having to duplicate code everytime you make the said request.

Those who have created end-to-end applications have mostly dealt with an interceptor and how to create it.

With Angular 2.x, the Interceptor has been put to bed and for good reasons. Read more here.

Why do I need an Interceptor?

Interceptors come in handy in multiple scenarios:

  1. Setting the Origin for each outgoing request.
  2. Adding authentication token to every request.
  3. Adding any custom header(s) that your application needs.

What are the alternatives?

With the lack of support for Interceptors in Angular 2.x, there have been a lot of supporting libraries that can help you create similar functionality. Some of the popular ones being:

Is there something easier?

If you are anything like me, you would fish around for easier/cleaner alternatives so that you can have minimal dependencies to maintain. This is the approach that I follow as it serves 99% of my needs without having a 3rd party library and allowing me to go ballistic with customizations.

Project Set Up

Before we get our hands dirty let us set up the project.

The easiest way to create an Angular 2.x application (if you don't have one already) is by using the Angular CLI.

To install it you need to have nodejs installed on you system. To install Angular CLI run the following command in terminal:

    npm install -g angular-cli

Once the CLI is installed, you can create a sample project using the commands:

    mkdir my-project
    cd my-project
    ng init

With that, you should have your app created and ready to go. Run the following command and open localhost:4200 in any browser to see your app in action.

    ng serve

Approach

In Angular 2.x we no longer have the concept of an Interceptor as mentioned above, but we are still going to call it an Interceptor for two reasons:

  1. It is still intercepting the requests.
  2. It is a familiar term and easy to understand for folks migrating from Angular 1.x.

But what's happening in the crux of it is that we are essentially modifying the request in a new class which extends the base Http class. We are then creating a factory which returns an instance of the newly created class when requested by the provider.

Now, lets break down the above statement into code:

essentially modifying the request in a new class which extends the base Http class

import {Injectable} from "@angular/core";
import { ConnectionBackend, RequestOptions, Request, RequestOptionsArgs, Response, Http, Headers} from "@angular/http";
import {Observable} from "rxjs/Rx";
import {environment} from "../environments/environment";

@Injectable()
export class InterceptedHttp extends Http {
    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
        super(backend, defaultOptions);
    }

    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        return super.request(url, options);
    }

    get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        url = this.updateUrl(url);
        return super.get(url, this.getRequestOptionArgs(options));
    }

    post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        url = this.updateUrl(url);
        return super.post(url, body, this.getRequestOptionArgs(options));
    }

    put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        url = this.updateUrl(url);
        return super.put(url, body, this.getRequestOptionArgs(options));
    }

    delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
        url = this.updateUrl(url);
        return super.delete(url, this.getRequestOptionArgs(options));
    }

    private updateUrl(req: string) {
        return  environment.origin + req;
    }

    private getRequestOptionArgs(options?: RequestOptionsArgs) : RequestOptionsArgs {
        if (options == null) {
            options = new RequestOptions();
        }
        if (options.headers == null) {
            options.headers = new Headers();
        }
        options.headers.append('Content-Type', 'application/json');

        return options;
    }
}

As you can see, before any of the requests are being fired, we are updating the URL of the request, so when you need to make a request instead of doing :

    this.http.get('http://mocker.egen.io/users')

all you would need to do is

    this.http.get('/users')

And you would need to create a constant called environment

    export const environment = {
        origin: 'http://mocker.egen.io'
    };

This gives you the flexibility to change the origin at anytime and make a code change within seconds.

We are then creating a factory which returns an instance of the newly created class

So now that we have the interceptor ready, we need the factory that will return an instance of the interceptor to the provider.

import {XHRBackend, Http, RequestOptions} from "@angular/http";
import {InterceptedHttp} from "./http.interceptor";

export function httpFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions): Http {
    return new InterceptedHttp(xhrBackend, requestOptions);
}

when requested by the provider

So this does not happen as explicitly as listed above but is a result of an implicit call made by the list of providers that are listed in the apps' main module.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import {HttpModule, Http, XHRBackend, RequestOptions} from '@angular/http';

import {AppComponent} from "./app.component";
import {httpFactory} from "./http.factory";

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule
    ],
    bootstrap: [AppComponent],
    providers: [
        {
            provide: Http,
            useFactory: httpFactory,
            deps: [XHRBackend, RequestOptions]
        }
    ]
})
export class AppModule { }

Conclusion

And thats it, you have a request interceptor up and running. You can find a full code sample here.

Kashyap Mukkamala

5 posts

I'm a Developer Advocate at Egen Solutions Inc, I fiddle around with JavaScript, Angular, Ionic & NativeScript during the day. Devoted Brogrammer.