Migrating Angular Interceptors to Function-Based Interceptors: A Step-by-Step Guide

Migrating Angular Interceptors to Function-Based Interceptors: A Step-by-Step Guide

Class-based interceptors for handling HTTP requests and responses has been a very useful Angular feature. However, Angular 14 introduced a more functional approach, allowing us to use function-based interceptors. This can simplify our code and make it more readable. In this blog post, we'll walk through the process of migrating from traditional class-based interceptors to function-based interceptors.

What Are Interceptors?

Interceptors are a powerful feature in Angular that allows you to intercept and modify HTTP requests and responses. They can be used for a variety of tasks such as adding authentication tokens, logging, error handling, and more.

Traditional Class-Based Interceptors

Let's start with an example of a traditional class-based interceptor which intercepts each http-request injects token:

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>> {
    const authToken = 'your-auth-token';
    const authReq = req.clone({
      headers: req.headers.set('Authorization', `Bearer ${authToken}`)
    });
    return next.handle(authReq);
  }
}

In this example, the AuthInterceptor class implements the HttpInterceptor interface, and the intercept method is used to modify the request by adding an authorization token to the headers.

Migrating to Function-Based Interceptors

Below is a step-by-step guide for migration.

Step 1: Creating the Function-Based Interceptor

First, let's rewrite the above class-based interceptor as a function:

import { HttpInterceptorFn } from '@angular/common/http';

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const authToken = 'your-auth-token';
  const authReq = req.clone({
    headers: req.headers.set('Authorization', `Bearer ${authToken}`)
  });
  return next(authReq);
};

In this function-based interceptor, we create an authInterceptor function that takes req (the request) and next (the next handler) as parameters. We modify the request to include the authorization token and then pass it to the next handler.

Step 2: Registering the Function-Based Interceptor

To use this function-based interceptor in your Angular application, you need to provide it in the module configuration. Modify your app.module.ts as follows:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, provideHttpClient, withInterceptors } from '@angular/common/http';
import { AppComponent } from './app.component';
import { authInterceptor } from './auth.interceptor';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [
    provideHttpClient(
      withInterceptors([authInterceptor])
    ),
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

In this setup, we use provideHttpClient to register the authInterceptor function as an HTTP interceptor.

Step 3: Testing the Function-Based Interceptor

Run the application and verify that the Authorization header is correctly added.

Advantages over class-based interceptor:

1. Ease of use
2. Easy configuration