Table of Contents
What is a HTTP Interceptor?
A HTTP Interceptor helps in intercepting and handling an HttpRequest or HttpResponse. It is available in @angular/common/http library.
In the previous article, we discussed in detail on how to make HTTP requests to APIs from an Angular Application and how HttpInterceptors help us in tweaking and fiddling the requests or responses as they move out of the application scope and before they reach their calling components.
We looked at how we can create our own HttpInterceptor by implementing the HttpInterceptor interface and for our requirement we’ve used it to add a default Request Header which must be passed on for all requests which are headed towards Posts API.
Some other possible applications of Interceptors are –
- adding an Authentication header which authorizes the client request at the API end.
- adding a timestamp query parameter at the end of all requests so that the API recognizes each request uniquely.
- capturing an ETag from the response headers as the response arrives from the API and preserve it.
- read response headers for any other required values.
Another use case of HttpInterceptors can be catching exceptions which might occur during an API request and handle these scenarios so that the calling components or services may not need to handle them explicitly, leading to a sort of safe-path for all HTTP requests.
How to catch HTTP Errors with HttpInterceptor with an Example
To implement this, we create another class ErrorInterceptor which implements HttpInterceptor and within the intercept() method.
Instead of working on the HttpRequest object like how we did before, we will now work with the result of a HTTP call, i.e, once the next.handle() returns to this interceptor.
Developing an Error Handler Interceptor
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
export class ErrorInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler)
: Observable<HttpEvent<any>> {
var res = next.handle(req);
res.pipe(
catchError((error: HttpErrorResponse) => {
// process the obtained error
// for logging or monitoring
console.log("Interceptor Log: " + error.message);
// create new Observable stream
// which the clients
// can subscribe and
// catch the Erroneous response
return throwError(error);
}));
}
}
Observe that we’ve added a pipe() to the HttpResponse Observable, which the next.handle(req) returns. This res object contains the result of the HTTP request which has been sent to the remote API and a response is awaited.
Using a pipe() we pull out the Response stream and then catch in case the response stream has thrown an exception in its course of HTTP request.
To catch the error, we use catchError – an RxJs operator which tracks the stream and catches any runtime errors which occur.
Within the catchError() we add a callback, to which the error of the type HttpErrorResponse is passed. Within this method, we can handle the error we have now caught and process it to any logging engine (like all other applications do) or do something else.
Handling Error at the Calling Component
Finally, we pass on the error using throwError() method, which creates a new Stream with the error that we’re now aware of. At clients, we can catch this error during the subscription and handle it according to the context.
this.postsUpdatedSubs = this.postsService.getPosts();
this.postsUpdatedSubs.subscribe((posts) => {
this.posts = [...posts];
}, (error) => {
// handle error
console.log("Error in PostListComponent: " + error.message);
});
Registering Interceptor in AppModule
We register this Interceptor at the AppModule level, so that it can be available for access across all the sub modules in the application.
@NgModule({
declarations: [
AppComponent,
NavbarComponent
],
imports: [
BrowserModule,
PostsModule,
AuthModule,
RouterModule.forRoot(routes)
],
providers: [{
provide: HTTP_INTERCEPTORS,
multi: true,
useClass: ErrorInterceptor
}],
bootstrap: [AppComponent]
})
export class AppModule { }
Observe that we have defined our ErrorInterceptor in the same way as we define any other HTTP Interceptor and attached it to the HTTP request pipeline.
Once we run the application, every HTTP request made by the application would pass through the ErrorInterceptor we just registered along with all other Interceptors created as well as the default ones built into the angular system.
When an error occurs, the ErrorInterceptor receives the error through the catchError() operator, where it gets access to the error object casted to HttpErrorResponse type.
It’s up to us how we can handle it: we can log it or do some analysis out of it or any other app specific operation.
Finally, we rethrow the error as a new Observable stream which the subscribed components receive and handle in their own way.
Conclusion
For example, back in our OpenSocialApp let’s run the application without having the API available, and see if the error is handled by the Interceptor as we expected.
As we can see in the logs printed on the Developer Console, the response passes through the ErrorInterceptor which first catches and prints the Error Log and later on is handled at the PostListComponent which also catches and reinitializes its posts model so that the view is not impacted of any issues.
Watch it here –
Extensive features, strong community support, comprehensive documentation, and vast ecosystem of libraries and tools make Angular a valuable skill to acquire for career growth in 2023.
Check out this most popular Angular course in Udemy at a HUGE DISCOUNT for a LIMITED PERIOD – Angular – The Complete Guide (2023 Edition) exclusive for our readers!