Introduction
Many of us know the concept of middleware. It acts as the layer before sending a request and after receiving a response. What if we want to do the same in Angular? Now, the question arises what will be the cases where we will be needing this middleware.
Let’s take an example of adding the headers before sending a request or logging all the responses to the activities we do. Imagine, we are adding the headers before each call to the server or we are logging the data after every Response or more specifically, handling all the HTTP errors at one place. How we can achieve the same using Angular? Interceptors is the answer for that.
Angular Interceptors
Interceptors are the mechanism where we can operate on the outgoing request and the incoming response.
It is the same concept of middleware that we use in the ASP.NET Core where we have these features. Interceptors are the layer between our Angular application and the back-end services. Whenever the request is made from the application, the interceptor catches the request, transforms it, and passes to the back end. The same happens with the response; whenever it receives the response, we can make changes to the response and use them in the application.
Setting up Interceptors
To set up interceptor, we need a class which will be injectable class and implementing the HttpInterceptor. When we implement this Interface, then we have a method called intercept which has the body like below.
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {}
It has two parameters "req" and "next" which are HttpRequest and HttpHandler respectively.
HttpRequest
This is the outgoing request which is being intercepted. It has various properties like URL, Header parameter, etc. One more thing we need to keep in mind is that this is the immutable object. To transform this object, we must clone this object and then send it into the HttpHandler.
HttpHandler
This sends the request to the next middleware or the data service that we have by using the handle method available for the object.
Next change we need to do, is to provide these interceptors in our root module as a service remember our interceptors are always the Injectable class so application module code change can be like below.
For our demonstration, we will add two interceptors which add the Headers in each request and then another for logging the response and catching the error and logging them.
I have added one folder called Interceptors which will hold our Header interceptor and Response Interceptor.
HeaderInterceptor
- import { Injectable } from '@angular/core'
- import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpResponse } from '@angular/common/http';
- import { Observable } from 'rxjs/Observable';
- import 'rxjs/add/operator/do';
-
- @Injectable()
- export class HeaderInterceptor implements HttpInterceptor {
- intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
-
- const dummyrequest = req.clone({
- setHeaders: {
- 'AuthKey': '12345', 'DeviceID': '85645',
- 'content-type': 'application/json'
- }
- })
- console.log("Cloned Request");
- console.log(dummyrequest);
- return next.handle(dummyrequest);
- }
- }
Above is the code for the HeaderInterceptor which will catch the request and adds header authkey,deviceid and content-type and sends them further for processing,
- We have imported the Injectable and the HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpResponse from the common/http, another package we need is the observable
- We have declared the class HeaderInterceptor which implements the HttpInterceptor. When we implement it, we get the method intercept which has HttpRequest and HttpHandler Object.
- In this method, we have cloned the request object and used the setHeaders method where we have set the authkey, deviceid, and the content-type of the request which is application/json
- Next, we are passing this object into the pipeline by using the handle method.
After adding this interceptor, when we see the output, it can be something like below.
Here we can see the request log and the headers we have added to the request.
Next, we will see the ResponseInterceptor which can be seen in the following code snippet.
- import { Injectable } from '@angular/core'
- import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpResponse } from '@angular/common/http';
- import { Observable } from 'rxjs/Observable';
- import 'rxjs/add/operator/do';
- @Injectable()
- export class ResponseInterceptor implements HttpInterceptor {
- intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
-
- console.log("Before sending data")
- console.log(req);
- return next.handle(req)
- .retry(3)
- .map(resp => {
- if (resp instanceof HttpResponse) {
- console.log('Response is ::');
- console.log(resp.body)
- }
- return resp;
- }).catch(err => {
- console.log(err);
- if (err instanceof HttpResponse)
- {
- console.log(err.status);
- console.log(err.body);
- }
-
- return Observable.of(err);
- });
-
- }
- }
- After importing the basic things like we have implemented the HttpInterceptor interface which can give us the intercept method.
- In that method, we have used the handle method of the Request which returns the observable and when we get the Observable we can use the map method to Transform the response.
- Next, we can check if the response is exactly the HttpResponse we received from server.
- Another benefit of this approach is the error handler and common log we can write the common error handle for overall application also the logger for the application.
Here we can see the response log as we have written in the application .we can see the response is logged in the console.
One more change that we need to do is the Application module changes, as follows.
- import { BrowserModule } from '@angular/platform-browser';
- import { NgModule } from '@angular/core';
- import { HttpClientModule,HTTP_INTERCEPTORS } from '@angular/common/http';
- import {FormsModule} from '@angular/forms'
- import { AppComponent } from './app.component';
- import { EmpoyeeHomeComponent } from './empoyee-home/empoyee-home.component';
- import {EmployeeDataService} from './DataService/DataService'
- import {HeaderInterceptor} from './Interceptors/HeaderInterceptor'
- import {ResponseInterceptor} from './Interceptors/ResponseInterceptor'
- @NgModule({
- declarations: [
- AppComponent,
- EmpoyeeHomeComponent
- ],
- imports: [
- BrowserModule,HttpClientModule,FormsModule
- ],
- providers: [EmployeeDataService,
- { provide: HTTP_INTERCEPTORS, useClass: HeaderInterceptor, multi: true }
- {provide:HTTP_INTERCEPTORS,useClass:ResponseInterceptor,multi:true}
- ],
- bootstrap: [AppComponent]
- })
- export class AppModule { }
Here, we can see the Providers section. We have injected our interceptors as a service in the provider section. We have added HTTP_INTERCEPTORS and their corresponding classes.
Summary
This was the basics of the interceptors and how we can use them to add some additional parameter in the request and then, to transform the response also to do some common logging and error handling mechanism.
Source code can be found at following location.
References
- https://alligator.io/angular/httpclient-interceptors/
- https://angular.io/