Angular HTTP Interceptors : Multiple Interceptors and 6 Code Examples of Interceptors

Swapnil Pakolu
9 min readFeb 6, 2019

--

Interceptors are used in Angular to Intercept HttpRequest/HttpResponse. We can use interceptors to log HttpRequest/HttpResponse, add additional headers to HttpRequest before passing it to server, make changes to request body or changing format of response received from server etc..

In this article I will explain how to use multiple interceptors and 6 most common uses of Interceptors with Example. By reading my article you will get a rough idea on overall aspect of interceptors :

I will discuss below listed topics in this article :

  1. How to add Multiple Interceptors ?
  2. Basics Steps to implement HttpInterceptor
  3. Examples of Interceptors
    i) Authentication / Session Interceptor
    ii) Request Format Interceptor
    iii) AJAX animation interceptor
    iv) Notify error interceptor
    v) TimeStamp interceptor
    vi) Retry Request Interceptor
  4. Using all Interceptors
  5. Github link
  6. Angular guide link:
  7. Thanks for reading 😃 ..

How to add Multiple Interceptors ?

Multiple Interceptors can be added in Angular with each Interceptor having different purpose. We can add all the functionalities within one interceptor but it may make things messy. So, to make the application modular we create different interceptors for different purpose.

Interceptors.ts :

  1. import HTTP_INTERCEPTORS from '@angular/common/http'
  2. import Interceptor services.
  3. Add all Interceptors in an array
export const interceptorProviders = [{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }];

HTTP_INTERCEPTOR : A multi-provider token which represents the array of HttpInterceptors that are registered.

const HTTP_INTERCEPTORS: InjectionToken<HttpInterceptor[]>;

provide: mention it as HTTP_INTERCEPTORS

useClass : mention the class which should be added to HttpInterceptors array

multi:true this is required setting which tells angular that token is multiprovider. The application will throw error if you set it to false.

app.module.ts :

  1. import HttpClientModule from '@angular/common/http'.
  2. import interceptorProviders from interceptors.ts. Add the InterceptorProviders array in providers array within @NgModule decorator in app.module.ts

Basics Steps to implement HttpInterceptor

basic-interceptor.service.ts :

  1. import Injectable from '@angular/core' and add @Injectable({providedId:'root'}) decorator to class to make it Angular Service.
  2. import HttpInterceptor from '@angular/common/http' Implement HttpInterceptor to make it Interceptor.
  3. import HttpRequest, HttpHandler, HttpEvent from '@angular/common/http' and implement intercept function as our class inherits/implements HttpInterceptor.
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>

4. intercept function will return next.handle(req);. It means that we are passing control to the next interceptor in the chain, if there is one.

next.handle(req);

You can also pass your own observable and short-circuit the interceptor chain and ignore the preceding interceptors and the backend handler. ex :-

return of(new HttpResponse<any>({body:'dummy body',url:'dummyurl.com'}));

Examples of Interceptors

Authentication / Session Interceptor

Authentication Interceptor can be used to add authentication header to your request. You can even route the application to login page if user is unauthenticated.

auth-interceptor.service.ts :

  1. Follow basic steps to implement HttpInterceptor
  2. add AuthService dependency within constructor parameter.
  3. check if user is authenticated using this.auth.isAuthenticated
  4. if user is authenticated add the authentication token to request header. here we are using request.clone() because request is immutable object.
  5. if user is unauthenticated route him to login page.

Request Format Interceptor

At times we may receive response from Api server in XML format. We need to convert format of the XML data to Json to use it in application. We can use interceptor to handle such responses.

xml2-json-interceptor.service.ts :

  1. Follow basic steps to implement HttpInterceptor.
  2. import NgxXml2jsonService from ‘ngx-xml2json’; (XML to JSON converter service)
    You need to install the package before using it in your project.
    npm install ngx-xml2json --save
  3. Import HttpResponse from '@angular/common/http';
  4. Change the expected response type to text instead of json. We make this change in order to receive XML as well as JSON response. If the response from server is in XML format and responsetype is 'json' we get following error SyntaxError: Unexpected token < in JSON at position 0 . So, to avoid error we change request in following way req = req.clone({ responseType: 'text'}); .
  5. Apply map operator to next.handel(req) . Note : we are using map operator instead of tap because we can only read the response using tap .
  6. Within the map operator if type of event is HttpResponse and if type of content is 'application/xml' we convert the body of event from Xml to Json using below code :
    const parser = new DOMParser();
    const xml = parser.parseFromString(event.body, ‘text/xml’);
    event = event.clone({ body: this.xml2jsonService.xmlToJson(xml) });

    We use event.clone(..) because HttpResponse if immutable.
  7. If type of event is HttpResponse and if type of content is 'application/json' we convert the body of event from text to Json using event = event.clone({body:JSON.parse(event.body)});. We are converting the body from text to json because we had requested response type as text but now we need the body in Json format so we can use it in application.

AJAX animation interceptor

One of the best example of interceptor in ajax animation interceptor. This interceptor will help you display a animation in your application whenever AJAX/XHR request is made by your Angular application. Mostly we add a loading animation to Header section of page. We have 3 sections for this service to work

  1. Interceptor : which will notify the directive.
  2. Notifier Service : which will contains current busy state of API requests. If there is any ongoing API request the value passed to busy will be true else it will be false.
  3. Directive : which will be added as an html attribute to the animation CSS or GIF which needs to be displayed when api Call occurs.

ajax-busy-identifier-interceptor.service.ts :

  1. Follow basic steps to implement HttpInterceptor.
  2. Call this.beginRequest(); at the beginning of intercept function. It will increment the requestCounter or set requestCounter as 1 if it is less than or equal to 0. If requestCounter is equal to 1 it will pass true to abns.busy BehaviourSubject. Which notifies the ajax-busy-indicator directive that ajax request has initiated.
  3. Call this.endRequest() within finalize(()=>{}). It will decrement the requestCounter if it is greater than 1 else set it equal to 0.
    if reequestCounter is equal to 0 we will pass false to abns.busy BehaviourSubject. Which will notify the ajax-busy-indicator directive that all ajax requests have finished(response received or failed).

ajax-busy-notifier.service.ts :

  1. AjaxBusyNotifierService contains property busy which is object of BehaviorSubject<boolean>;. BehaviorSubject<boolean> behaves as observable as well as observer. In the interceptor it behaves as observer when it calls abns.busy.next(true) . In Directive It will behave like observable when it calls abns.busy.subscribe((busy)=>{…}) .

ajax-busy-indicator.directive.ts :

  1. Add @Directive decorator AjaxBusyIndicatorDirective class to make it directive.
  2. Add selector:'[ajax-busy-indicator]' option to the decorator. This will make it attribute directive. Now we can add ajax-busy-indicator to any element to apply this directive.
  3. Declare showDelay and hideDelay variable and add @Input decorator to make it input attributes for the directive.
  4. Declare showTimer and hideTimer Subscription objects so we can unsubscribe show and hide timers.
  5. cancelPendingHide() will unsubscribe the hideTimer and cancelPendingShow() will unsubscribe the showTimer.
  6. Within ngOnInit we will add 2 subscribers to our abns.busy BehaviourSubject . One to hide the content(loading animation) and other to show the content within directive.
  7. if the value passed to abns.busy is true
    a) it will call cancelPendingHide() to unsubscribe to hideTimer.
    b) it will initiate the timer with showDelay as period of timer . Within the timer it will remove'inactive' class from directive element and then unsubscribe the timer and make timer null.
  8. Similarly we will do inverse if abns.busy is false.

Notify error interceptor

Notify error interceptor can be used to display error if response of the AJAX/XHR request is error.

error-notifier.service.ts :

  1. Follow basic steps to implement HttpInterceptor.
  2. Import ToastrService from ngx-toastr. Inject ToastrService dependency using constructor.
    constructor(private toasterService: ToastrService){}. Before using ToasteService we need to install it using npm :
    npm install ngx-toastr — save
    @angular/animations package is a required dependency for the default toast npm install @angular/animations --save
  3. Within intercept function apply tap operator tonext.handle(request) Observable using pipe function. Tap the error and display it using toasterService .

TimeStamp interceptor

Request timestamp interceptor service is used to log the total response time for a particular request. We also add startTime and endTime header to the response header which can be used within the application as well.

request-timestamp.service.ts :

  1. Follow basic steps to implement HttpInterceptor.
  2. Within intercept function declare startTime variable and set it to current time that is time when application made the http request.
    var startTime = (new Date()).getTime();
  3. Apply map operator to next.handle(req) Observable using pipe function. Within map operator declare the endTime variable and set it equal to current time i.e. the time on which we received response.
  4. Add startTime and endTime header to the Response.
    event = event.clone({ headers: event.headers.set(‘endTime’, endTime.toString()) });
    event = event.clone({ headers: event.headers.set(‘startTime’, startTime.toString()) });
  5. Calculate the difference between startTime and endTime and store it in variable diff. Display the time using console.
  6. Apply tap operator to next.handle(req) Observable using pipe function. Within tap operator error =>{}declare variable endTime and set it to current time i.e. the time on which the response failed.
  7. Calculate the difference between endTime and StartTime and display it in console.
  8. Note we are using map operator to modify response and display total time while we are using tap operator to display only total time for error.
    a) This is because map operator can be used to tap the response but not error.
    b) We can modify the header of response using map operator but not using tap.
    c) We cannot add headers to error because error.headers is read-only property.

Retry Request Interceptor

Retry Request Interceptor is used to retry the request in case of failure. Sometimes the failure may occur due to poor connection. To encounter this issue we may apply retry operator.

retry-interceptor.service.ts :

  1. Follow basic steps to implement HttpInterceptor.
  2. Within intercept function apply retry operator to next.handle(req) Observable using pipe function.
    return next.handle(req).pipe(retry(3));
  3. retry(3) this will retry the request 3 times.

Using all Interceptors

Now we will check how all this Interceptors work. Basically I will show how I invoked different type of API’s to display use of all The Interceptors mentioned above.

  1. We have added 3 buttons
    a) Request Data button will display use of RequestTimestampService and AjaxBusyIdentifierInterceptorService
    b) Request XML Data button will display use of RequestTimestampService, AjaxBusyIdentifierInterceptorService and XML2JsonInterceptorService
    c) Request 404 Data button will display use of RequestTimestampService, AjaxBusyIdentifierInterceptorService, ErrorNotifierService and RetryInterceptorService .

Request Data :
When we click on Request data button we send GET request to https://jsonplaceholder.typicode.com/todos/1 URL which responds with JSON data. (JSONPlaceholder is a free online REST API that you can use whenever you need some fake data).
a)RequestTimestampService will display the total time required in console
b)AjaxBusyIdentifierInterceptorService will help us display the Ajax Loading Indicator in the header .(in below screenshot you can view the loading animation in top left corner of the screen).

response received on request Data button click

Request XML Data :
When we click on Request data button we send GET request to https://api.openweathermap.org/data/2.5/weather?q=London&mode=xml&appid=myApiID URL which responds with XML data. (using openweatermap we can request weather information which is free api service great for leaning purpose)
a) RequestTimestampService will display the total time required in console b)AjaxBusyIdentifierInterceptorService will help us display the Ajax Loading Indicator at the top.
c) XML2JsonInterceptorService will convert the XML response to JSON response

response received on “request XML Data” button click
response received from server in XML converted to JSON using interceptor.

In above screenshot we can see that the response received was in XML format which was converted to JSON using our interceptor.

Request 404 Data :
When we click on Request 404 Data button we send GET request to https://jsonplaceholder.typicode.com/todos/7878 URL which responds with 404 error data.
a) RequestTimestampService will display the total time required in console b)AjaxBusyIdentifierInterceptorService will help us display the Ajax Loading Indicator at the top.
d)ErrorNotifierService will display the error dialogue box
e) RetryInterceptorService will retry the request 3 times but the ErrorNotifierService will display the error message only once because RetryInterceptorService is added afterwards.

Angular applies interceptors in the order that you provide them. If you provide interceptors A, then B, then C, requests will flow in A->B->C and responses will flow out C->B->A.
- Angular Docs

Display of use of error notification interceptor and retry request interceptor.

Github link

You can find the source code of Interceptors project in below github link

https://github.com/SwapnilPakolu/Interceptors

Angular guide link:

https://angular.io/guide/http#intercepting-requests-and-responses

Thanks for reading 😃 ..

Thanks for making it till end. I hope my blog was helpful to you 😄 . Please let me know in comment down below if you have any queries or suggestions. I have tested all the examples demonstrated in this article 😏 still if you find any of the example incorrect 😞 in anyway please let me know I will try to fix it 😁

Please give a clap 👏 for my article 😀😛 if you think it was useful.

Thanks,

Swapnil Pakolu

--

--