Intercept HTTP Requests in Angular
Angular version 4.3.1 introduced one important new feature: the new HTTP client. Not only did it bring optimizations in how we can execute requests to backend APIs, but it made intercepting HTTP requests extremely easy.
Contents are based on Angular version >= 4.3.1
Learn everything about the new Http client introduced in Angular 4.3 and now default in Angular 5 in my latest Egghead.io video course on “Learn HTTP in Angular”.
In the following Egghead.io video lesson I implement an HTTP interceptor which intercepts the request, adding some headers, the response as well as potential HTTP errors.
The new HTTP client
Installing and Registering
The new HTTP client resides in the @angular/common
package under the @angular/common/http
. You need to register the HttpClientModule
and register the interceptor on the HTTP_INTERCEPTORS
.
// app.module.ts
...
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
// your interceptor file
import { MyHttpLogInterceptor } from './http.interceptor';
@NgModule({
imports: [ ..., HttpClientModule ],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: MyHttpLogInterceptor, multi: true }
],
...
})
export class AppModule {}
An HTTP interceptor is just an Angular service implementing a specific interface, the HttpInterceptor
.
// http.interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class MyHttpLogInterceptor implements HttpInterceptor {
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return next.handle(request);
}
}
Intercepting HTTP requests
To intercept the request before it is sent to the server, we need to clone the request object and accordingly add the information we want.
@Injectable()
export class MyHttpLogInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
...
// add a custom header
const customReq = request.clone({
headers: request.headers.set('app-language', 'it')
});
// pass on the modified request object
return next.handle(customReq);
}
}
Intercepting HTTP responses
To intercept the response coming back from the server, we can simply hook on the do(..)
operator as the new HTTP module heavily relies on the Observable API.
...
import {
HttpInterceptor,
HttpRequest,
HttpResponse,
HttpErrorResponse,
HttpHandler,
HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { tap } from 'rxjs/operators';
@Injectable()
export class MyHttpLogInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
...
return next
.handle(customReq)
.pipe(
tap((ev: HttpEvent<any>) => {
if (ev instanceof HttpResponse) {
console.log('processing response', ev);
}
})
)
}
}
Intercepting HTTP request errors
Similarly, for catching response errors, the catch
Observable operator can be used.
import {
HttpInterceptor,
HttpRequest,
HttpResponse,
HttpErrorResponse,
HttpHandler,
HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { tap, catchError } from 'rxjs/operators';
import { throwError } from "rxjs";
@Injectable()
export class MyHttpLogInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
...
return next
.handle(customReq)
.pipe(
tap((ev: HttpEvent<any>) => {
...
}),
catchError(response => {
if (response instanceof HttpErrorResponse) {
console.log('Processing http error', response);
}
return throwError(response);
})
)
}
}
Runnable Plunker
That’s it. Check out the Egghead video lesson at the beginning of this article or simply start playing straight away with this runnable Plunker. Just open it in another window and inspect the console.log
statements on the your browser’s devtools.
Common mistakes/pitfalls
Here are some common mistakes or pitfalls I came across when using interceptors in Angular.
CreateListFromArrayLike called on non-object
Strange error, not very expressive. The issue occured to me when setting custom headers, especially when not converting the header values to a string before setting them.
// WRONG
...
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
// header value send as number
const newRequest = req.clone({ headers: req.headers.set('somekey', 11234) });
return next.handle(newRequest);
}
...
// CORRECT
...
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
// header value needs to be sent as string
const newRequest = req.clone({ headers: req.headers.set('somekey', '11234') });
return next.handle(newRequest);
}
...