Angular 15: interceptor as a function

nicoss54

Nicolas Frizzarin

Posted on January 11, 2023

Angular 15: interceptor as a function

Introduction

The release of Angular 14 made it possible to use the inject function outside the injection context. This has unlocked some features like:

  • the composition pattern
  • creation of guards as a simple function

With the release of Angular 15, it is around the interceptors to benefit from this writing.
However, the interceptors are linked to the httpClient instance and with the introduction of optional modules several questions arise:

  • how to register now the http client?
  • how to write an interceptor as a simple function?
  • how to register it?
  • is it possible to have interceptors as class and interceptors as functions in a same application?

The new way to register the http client

Before the release of Angular 15, if we wanted to bootstrap on a standalone component and provide the http client of Angular, we had to use the importProvidersFrom(module) function which take care of:

  • importing the providers exported by the module
  • registering the providers in the environment injector
bootstrapApplication(AppComponent, {
  providers: [ importProvidersFrom(HttpClientModule) ]
}).catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Now with Angular 15, Angular exposes a new function called provideHttpClient which allows to simply register the http client.
This function takes as parameter a list of HttpFeature. A concrete example of HttpFeature is the registration of interceptors.

bootstrapApplication(AppComponent, {
  providers: [ provideHttpClient() ]
}).catch(console.error);
Enter fullscreen mode Exit fullscreen mode

The new way to write interceptor and to register them

Before Angular 15, an interceptor was always a class preceded by the @Injectable annotation.
This writing was very useful because it allowed us to inject our providers.

@Injectable()
export class AuthorizationInterceptorDI implements HttpInterceptor {
  constructor(private loadingService: LoadingService){}
  intercept(request: HttpRequest<any>>, next: HttpHandler): Observable<HttpEvent<any> {
    this.loadingService.startLoader();
    const clonedRequest = request.clone({ setHeaders: { Authorization: 'this_is_angular' } });
    return next.handle(clonedRequest)
      .pipe(finalize(() => this.loadingService.stopLoader());
  }
}
Enter fullscreen mode Exit fullscreen mode

Thanks to the fact that the inject function can be used outside the injection context, this class can be transformed into a function.

export function AuthorizationInterceptor(req: HttpRequest<unknown>,
next: HttpHandlerFn){
    const loadingService = inject(LoadingService);
    loadingService.startLoader();
    const clonedRequest = request.clone({ setHeaders: { 
      Authorization: 'this_is_angular' } });
    return next(clonedRequest)
      .pipe(finalize(() => this.loadingService.stopLoader()))
}
Enter fullscreen mode Exit fullscreen mode

An interceptor function takes two parameters

  • the request on which the interceptor will interact
  • a function that allows to send the transformed request

The return of this function must be an observable of type HttpEvent to be able to interact with the response of the http request.

To add an interceptor function in the httpClient instance, Angular gives us a new withInterceptors function.

This function takes as parameter an array of interceptors function and returns an HttpFeature of type interceptor.
This type of return is very useful because it allows later to call this function in the provideHttpClient function.

bootstrapApplication(AppComponent, {
  providers: [ provideHttpClient(
    withInterceptors([AuthorizationInterceptor])) 
  ]
}).catch(console.error);
Enter fullscreen mode Exit fullscreen mode

There are many other functions that return an HttpFeature. It is the case for example of the functions

  • withXsrfConfiguration which allows the customization of the XSRF protection
  • withJsonpSupport which allows the support of JSONP in Http requests

More information here.

Is it possible to mix ?

In an Angular application, it is now possible to have standalone components and modules. This cohabitation can be very practical if you want to migrate step by step an application based on modules to an application based only on standalone components.

In this idea, if our application bootstrap now on a standalone components and so we use the provideHttpClient function to register the http client, is it necessary to migrate all interceptors to the new function format?

The answer is ... NO. It is possible to make interceptors in function format and interceptors in class format coexist.
To do this Angular provides us with a special function: withInterceptorsFromDi

The withInterceptorsFromDi function is intended to add the interceptors registered in the old format:

{ provide: HTTP_INTERCEPTORS,
  useClass: AuthorizationInterceptorDI
  multi: true
}
Enter fullscreen mode Exit fullscreen mode

to the httpClient istance.

bootstrapApplication(AppComponent, {
  providers: [ provideHttpClient(
    withInterceptorsFromDi()) 
  ]
}).catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Thanks to these two distinct functions, it is possible to make the two syntaxes cohabit within the same Angular application, and thus allow a progressive migration.

Conclusion

Angular 15 allows the stabilization of standalone components and allows to continue the removal of boilerplating.
The new syntax of interceptors in function format is lighter than the previous one.

Thanks to the functions withInterceptors and withInterceptorsFromDi, the interceptors can be migrated step by step.

Nevertheless, prefer from now on the syntax in function format and the use of withInterceptors because the function withInterceptorsFromDi risks to be removed in the future versions of Angular.

💖 💪 🙅 🚩
nicoss54
Nicolas Frizzarin

Posted on January 11, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Angular 15: interceptor as a function
angular Angular 15: interceptor as a function

January 11, 2023

What You Need to Know about Angular v13
angular What You Need to Know about Angular v13

November 10, 2021