How to Use Interceptors in Angular

Eugeniu Cozac
5 min readApr 20, 2021

Frontend development for single-page applications (SPAs) is really at a boom in today’s era due to the unmatched benefits that it offers. In this article, we will discuss one of the key concepts that Angular has introduced within its framework i.e. interceptors. We will look briefly at what interceptors are, how they can be used, and what are the benefits of using them in our application. So let’s start!

What are Interceptors?

In order to scale up a large application, Angular provides various built-in tools to facilitate the development process. Interceptors are one of the most powerful built-in tools in Angular that are used to handle HTTP requests at a centralized origin or at a global level. Since they are concerned with HTTP request and response cycles so they are also commonly called HTTP interceptors. Placing the commonly used logic at the application level and enabling the code flow to utilize that logic at runtime is an extremely cool concept that helps reduce redundancy in code and hence contributes towards a clean, maintainable, and scalable codebase.

Common Ways to Use HTTP Interceptors

Let’s now look at some of the most popular use cases (with code) in which using interceptors can prove beneficial. Before proceeding with the use cases, let’s understand how we can create an interceptor first.

You can create a separate TypeScript file for the interceptor as follows.

// PACKAGE IMPORTS
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
HttpErrorResponse
} from ‘@angular/common/http';
import {
Observable,
throwError
} from 'rxjs';
import {
catchError
}
from 'rxjs/operators';
// INTERCEPTOR CLASS
export class DummyInterceptor implements HttpInterceptor
{
intercept(request: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>>
{
return next.handle( request)
}
}

The above code defines the structure of initiating the definition of interceptors. The DummyInterceptor class is our custom interceptor which must implement the HttpInterceptor interface. This is because the abstract method intercept inside HttpInterceptor is responsible for letting Angular know that any code written inside this method must be intercepted for HTTP
requests. The intercept method takes in two parameters; the first is the actual HttpRequest and the other is the HttpHandler object.

Having understood how to create the basic outline for an interceptor, let’s understand its use cases now.

Error Handling

Oftentimes, we do a common set of steps whenever we encounter an error in response. Let’s say you want to show a popup when an error occurs, or just as simple as logging the error during the development process, you can create an interceptor that can do this for you and save the code redundancy.

// INTERCEPTOR CLASS
export class ErrorInterceptor implements HttpInterceptor
{
intercept(request: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>>
{
return next.handle( request)
.pipe(
catchError((error: HttpErrorResponse) =>
{
if (error.status === 404)
{
console. log('Object Not Found Error');
}
return throwError(errorMsg) ;
}))
}
}

The above piece of code simply logs those errors to the console which has the status code of 404. Simple enough, right? Instead of doing it for every single endpoint and service, we created an interceptor!

Header Manipulation

You can also use interceptors for manipulating headers of requests. Suppose you had to add a new key to the headers or modify an existing key, you can do that in a separate interceptor dedicated to the header.

// INTERCEPTOR CLASS
export class RequestHeaderInterceptor implements HttpInterceptor
{
intercept(request: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>>
{
const newRequest = req.clone({
setHeaders: { "Encrypted-Code": "qwTg345DFhgJFS5Thd9j" }
});
return next.handle(newRequest);
}
}

Configuring Loaders

For every request and response cycle, there is a network delay that users have to face before they see the actual response. Mostly, applications show a loader when the user makes a request so that they explicitly know that response is being processed. It is an effective UX strategy. Since, ideally, we would want to show loader for delays in every request-response cycle, instead of doing that in every service separately, why not just simply create an interceptor for that?

// INTERCEPTOR CLASS
export class LoaderInterceptor implements HttpInterceptor
{
intercept(request: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>>
{
const loaderService = this.injector.get(LoaderService);
loaderService.show();
return next.handle(req)
.pipe(
delay(5000),
finalize(() => loaderService.hide()));
}
}

The above code shows the loader as soon as the request is made and hides it accordingly.

Configuring Notifications

Just how we handled popups, we can also configure the logic for notifications in interceptors as per how we wish to handle them.

// INTERCEPTOR CLASS
export class NotificationInterceptor implements HttpInterceptor
{
intercept(request: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>>
{
return next.handle(req)
.pipe(
tap((event: HttpEvent<any>) =>
{
if (event instanceof HttpResponse & event.status === 201)
{
// Or any other custom logic
console. log("Successfully created object.");
}
}));
}
}

In the above code, we check if the status of the response is 201, we write our code to handle this specific case differently. For the sake of simplicity, we are just logging but you can implement any custom logic you wish.

These are just a few common use cases of using interceptors. The other similar use case of using interceptors can be injecting authentication token, URL manipulation, caching, profiling/logging, format conversion, etc.

Benefits of Using Interceptors

By now, we looked at how uniquely we can make use of Angular’s HTTP interceptors in a lot of creative manners. They offer a great range of benefits to the modern application development paradigm. Following are a few of the key benefits of using interceptors.

  1. Code reusability — since we are expected to perform a certain common set of steps against a majority of the HTTP requests and responses, we can write the logic in one place and enable the request and response flow to use that logic. This way, instead of replicating the same logic individually on a service level, we write that once and hence it produces a lot less redundant code which is also a clean practice to follow.
  2. Scalability — this point is, kind of, linked to the first point in a way that it provides an extension to the idea stated earlier. If the code is reusable then it automatically makes sense that it will be a lot easier to scale the code and its design.
  3. Better service layer — since we can handle the related activities using interceptors, we do not need to pollute the service layer with handling that other stuff. This way, the service layer will be clean, to-the-point, and will only do what it is responsible for doing.

Conclusion

That was all about HTTP interceptors in Angular. Pretty interesting concept, right? Let’s hope that after reading this, the developers will feel a lot more motivated while designing Angular services, utilize the benefits of interceptors, and keep the service logic short, concise, to-the-point, maintainable, and scalable.

--

--

Eugeniu Cozac

JavaScript Developer. I am proficient in building SPA with React.js