Mastering HTTP Interceptors in Angular
In modern web development, handling HTTP requests and responses efficiently is crucial for creating a seamless user experience. Angular provides a powerful feature called HTTP Interceptors that allows you to intercept and manipulate HTTP requests and responses before they reach the backend or the frontend application.
This article will guide you through the concept of HTTP Interceptors in Angular, showcasing how they can be used for tasks such as adding authentication tokens, modifying headers, logging requests, handling errors, and more.
What are HTTP Interceptors in Angular?
HTTP Interceptors in Angular are part of the HttpClientModule and allow you to intercept HTTP requests and responses. Interceptors are services that can be used to:
- Modify the request before it’s sent to the server.
- Transform or modify the response before passing it to the subscriber.
- Handle or log errors that occur during the request-response cycle.
They are implemented by creating a service that implements the HttpInterceptor
interface, which provides methods to manipulate requests and responses.
How HTTP Interceptors Work in Angular
HTTP interceptors are chainable, meaning multiple interceptors can be used in sequence. When a request is made, the request passes through all active interceptors before it reaches the backend API. Similarly, when the response is returned, it passes through each interceptor before it is handed to the component.
An HttpInterceptor needs to implement the intercept()
method, which accepts two parameters: the HttpRequest and HttpHandler. It’s the job of the intercept()
method to modify the request or handle the response.
Creating an HTTP Interceptor in Angular
Let’s walk through the steps to create a simple HTTP Interceptor in Angular:
1. Set Up Angular Project
Ensure you have an Angular project set up with the HttpClientModule imported. If you don't have this set up yet, do so by running:
ng new angular-http-interceptor
cd angular-http-interceptor
ng add @angular/common/http
2. Create the Interceptor Service
Create an interceptor service by running:
ng generate service interceptors/auth
auth.interceptor.ts
file and implement the HttpInterceptor
interface:import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable() export class AuthInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // Clone the request and add the authorization header const clonedRequest = req.clone({ setHeaders: { Authorization: `Bearer your-token-here` } }); // Pass the cloned request to the next handler in the chain return next.handle(clonedRequest); } }
In this example, we are adding an Authorization
header to every HTTP request. You can modify this logic to suit your needs, such as adding custom headers, logging requests, or modifying request body content.
3. Provide the Interceptor in App Module
After creating the interceptor, you need to register it in the AppModule
so Angular knows to use it. Open app.module.ts
and add the interceptor in the providers
array:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AppComponent } from './app.component';
import { AuthInterceptor } from './interceptors/auth.interceptor';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HttpClientModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
By setting multi: true
, you ensure that Angular allows multiple interceptors to be used.
Common Use Cases for HTTP Interceptors
Adding Authentication Tokens: One of the most common use cases for an HTTP interceptor is adding an authentication token to requests. This ensures that the user is authorized to access protected resources.const clonedRequest = req.clone({
setHeaders: {
Authorization: `Bearer ${this.authService.getToken()}`
}
});
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next.handle(req).pipe( catchError(error => { if (error.status === 401) { this.authService.logout(); } return throwError(error); }) ); }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { console.log('Request:', req); return next.handle(req).pipe( tap(event => { if (event instanceof HttpResponse) { console.log('Response:', event); } }) ); }
Content-Type
or adding custom headers based on certain conditions.intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const clonedRequest = req.clone({ setHeaders: { 'X-Custom-Header': 'customValue' } }); return next.handle(clonedRequest); }
Best Practices for Using HTTP Interceptors
- Use for Cross-Cutting Concerns: HTTP interceptors are perfect for tasks that should be handled globally, such as logging, caching, authentication, and error handling.
- Chain Multiple Interceptors: You can chain multiple interceptors to handle different concerns. Angular will execute them in the order they are registered in the
providers
array. - Avoid Modifying Response Directly: While it's possible to modify the response, it is generally better to use interceptors to modify the request and handle errors, not to transform the actual response data. For that, services or components are better suited.
Conclusion
HTTP interceptors in Angular provide a powerful way to handle and manipulate HTTP requests and responses globally. They allow for tasks like adding authentication headers, logging HTTP traffic, managing errors, and more. Interceptors help improve the maintainability and scalability of your application by centralizing cross-cutting concerns.
By incorporating interceptors into your Angular application, you can streamline request and response handling, improve security, and ensure a more robust user experience across all HTTP interactions.