Img
Deepak AsatiSoftware Developerauthor linkedin
Published On
Updated On
Table of Content
up_arrow

Understanding Angular Interceptors: A Powerful Tool for HTTP Requests and Responses

In modern web applications, managing HTTP requests and responses efficiently is crucial. Whether you're dealing with authentication, error handling, logging, or even showing loading indicators, it can quickly get overwhelming. That's where Angular Interceptors come into play.

Angular-Interceptor

What Are Angular Interceptors?

At its core, an interceptor in Angular is a way to intercept and modify HTTP requests and responses before they are sent to the server or when the response is received in your application. Think of it like a middleman that sits between your application and the HTTP requests your app makes.

Interceptors provide a centralized, reusable way to handle common tasks such as:

  • Modifying requests (e.g., adding authentication tokens).
  • Transforming responses (e.g., normalizing data formats).
  • Error handling (e.g., logging or retrying failed requests).
  • Implementing global features like logging, caching, or progress indicators.

In short, interceptors let you implement cross-cutting concerns in a clean and maintainable way, instead of duplicating logic in multiple places.

How Do Angular Interceptors Work?

In Angular, interceptors are implemented using the Http Interceptor interface, which has a single method: intercept. The intercept method allows you to take control over the HTTP request and response flow. Here's the basic structure of an interceptor:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';  
import { catchError } from 'rxjs/operators';  

@Injectable()
export class MyInterceptor implements HttpInterceptor {

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>   {
// Modify the request before sending it
const clonedRequest = req.clone({
setHeaders: { Authorization: 'Bearer token' }
});

// Pass the modified request to the next handler in the pipeline
return next.handle(clonedRequest).pipe(
catchError((error) => {
console.error('HTTP request failed', error);
throw error; // Re-throw or handle the error
})
);
}
}


  • req: HttpRequest<any>: This is the original HTTP request. It contains all the details like URL, headers, body, and so on.
  • next: HttpHandler: This is the next step in the HTTP pipeline. Once you've modified the request (if necessary), you call next.handle() to forward it.
  • clone(): The request is immutable in Angular. If you want to modify it (for example, by adding headers), you use req.clone() to create a modified copy.
  • catchError: This operator is used to catch any errors in the HTTP response and allows you to handle them globally.

When Should You Use Angular Interceptors?

Now that we know how interceptors work, let's explore the common use cases for interceptors in Angular. These use cases cover a wide range of situations that we often encounter in real-world apps.

1. Authentication and Authorization

One of the most common use cases for interceptors is to add an authentication token (such as a JWT) to the HTTP request headers. This allows your app to securely communicate with the backend, ensuring that each request is authorized.

Imagine you're building an app that requires users to log in, and you need to attach a JWT token to every request. Instead of manually adding the token to each HTTP request, you can centralize the logic in an interceptor.

Example:

export class AuthInterceptor implements HttpInterceptor {

constructor(private authService: AuthService) {}

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

const token = this.authService.getToken();

const clonedRequest = req.clone({
setHeaders: { Authorization: `Bearer ${token}` }
});

return next.handle(clonedRequest);
}

}

2. Global Error Handling

Interceptors are also handy when you want to handle errors globally. For example, if the backend returns a 401 Unauthorized error (perhaps the token has expired), you can catch this error in your interceptor and perform actions such as logging the user out and redirecting them to the login page.

Example:

export class ErrorInterceptor implements HttpInterceptor {

constructor(private authService: AuthService, private router: Router) {}

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
catchError((error) => {
if (error.status === 401) {
// Handle unauthorized error
this.authService.logout();
this.router.navigate(['/login']);
}
return throwError(error);
})
);
}

}

3. Request and Response Transformation

In some scenarios, you may need to transform the request before it’s sent to the server or the response once it’s received. For example, you might want to automatically format dates or convert all strings to uppercase.

Example:

export class DateTransformInterceptor implements HttpInterceptor {

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

if (req.body && req.body.date) {
// Convert date to a specific format
req = req.clone({
body: { ...req.body, date: formatDate(req.body.date) }
});
}

return next.handle(req);
}

}

4. Adding Global Headers

You might want to add global headers to every HTTP request, such as setting the Content-Type or Accept headers for all outgoing requests. Instead of manually adding headers to every request, you can use an interceptor to apply these headers globally.

Example:

export class HeaderInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const clonedRequest = req.clone({
setHeaders: { 'Content-Type': 'application/json' }
});
return next.handle(clonedRequest);
}
}

5. Progress Indicators (e.g., Loading Spinners)

A very user-friendly use case for interceptors is showing a loading spinner while the HTTP request is in progress. Once the response is received (or the request fails), you can hide the spinner.

Example:

export class LoadingInterceptor implements HttpInterceptor {
constructor(private loadingService: LoadingService) {}

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.loadingService.show();
return next.handle(req).pipe(
finalize(() => {
this.loadingService.hide();
})
);
}
}

How to Register an Interceptor in Angular?

To use an interceptor in your Angular application, you need to register it in the AppModule. Angular provides a special injection token called HTTP_INTERCEPTORS that allows you to provide one or more interceptors.

Here’s how to register an interceptor:

import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './auth.interceptor';
import { ErrorInterceptor } from './error.interceptor';

@NgModule({
imports: [HttpClientModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true // Allows multiple interceptors
},
{
provide: HTTP_INTERCEPTORS,
useClass: ErrorInterceptor,
multi: true
}
]
})
export class AppModule {}


The multi: true flag ensures that multiple interceptors can be used together without overriding each other.

Conclusion

Angular interceptors are a powerful tool that can help you manage HTTP requests and responses in a clean and centralized manner. They provide an elegant way to handle common tasks such as authentication, error handling, data transformation, and even global features like loading indicators and headers.

By using interceptors, you can keep your application logic clean and avoid repetitive code in individual components or services. They allow you to focus on writing business logic instead of managing HTTP concerns across your app.

What is the purpose of interceptor in Angular?


In Angular, interceptors serve as a powerful way to manipulate HTTP requests and responses. They can be used for various tasks such as:

  • Adding authentication headers to outgoing API requests.
  • Retrying failed requests using techniques like exponential backoff.
  • Caching responses for a specific duration or until the data is invalidated by changes.
  • Logging or modifying requests and responses globally across the application.
  • Handling errors or displaying loading indicators during requests.


Interceptors are applied globally and allow developers to modify the behavior of HTTP calls in a centralized manner.

Can we use multiple interceptors in Angular?


Yes, you can use multiple interceptors in Angular. Interceptors can inspect and modify both HTTP requests sent from your application and responses received from the server. When multiple interceptors are used, they form a chain where each interceptor can process the request before it is sent and the response after it is received. This allows for flexible and modular handling of common tasks such as authentication, error handling, logging, and more, by applying different logic in each interceptor along the request/response flow.


What is an interceptor in Angular, and how is it used?


In Angular, an interceptor acts as middleware that intercepts and modifies HTTP requests and responses. It allows you to perform actions before the request is sent to the server or after the response is received. Interceptors are useful for tasks such as adding authentication tokens, handling errors globally, logging, or transforming responses before they reach the application. They work on both the request and response level, providing a centralized way to manage HTTP interactions.


What are Angular interceptors for error handling?


Angular interceptors are essential tools for handling HTTP requests and responses globally, offering greater control over communication with the backend. For error handling, interceptors enable you to catch errors in one centralized location, eliminating the need to manage errors individually in every component or service. They allow you to modify error responses, convert server error messages into user-friendly formats, log errors automatically, and even retry failed requests using strategies like exponential backoff. By managing errors in a consistent and streamlined way, interceptors make applications more resilient and easier to maintain.

Schedule a call now
Start your offshore web & mobile app team with a free consultation from our solutions engineer.

We respect your privacy, and be assured that your data will not be shared