Entwickler schreibt Code am Computer
Dennis, Kiya | 14.08.2023

Migration from Angular's Class-Based Interceptors to Function-Based Interceptors

Webentwicklung > Migration from Angular's Class-Based Interceptors to Function-Based Interceptors

From Class-Based to Function-Based Interceptors

In this article, we'll explore how to migrate from class-based interceptors to function-based interceptors. With the release of Angular v15, the Angular team introduced a new way to create interceptors. Instead of creating a class that implements the HttpInterceptor interface, we can now create a function that implements the HttpInterceptorFn interface.

Why should we migrate to function-based interceptors?

Class-based interceptors are great, but they might be deprecated in a later version. An indicator of this is for example: withInterceptorsFromDi() 🤔

In addition to this, function-based interceptors are better than class-based interceptors for several reasons:

  • Easier usage

  • Quick creation

  • Simple configuration

Migration of the AuthorizationInterceptor to a function-based interceptor

The interceptor currently looks like this:

1import { Injectable, inject } from '@angular/core';
2import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
3import { Observable, mergeMap, tap } from 'rxjs';
4import { AngularFireAuth } from '@angular/fire/compat/auth';
5
6@Injectable()
7export class AuthorizationInterceptor implements HttpInterceptor {
8    readonly angularFireAuth = inject(AngularFireAuth);
9
10    intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
11        if (request.url.indexOf('oauthCallback') > -1) {
12            return next.handle(request);
13        }
14        return this.angularFireAuth.idToken.pipe(
15            mergeMap((token) => {
16                if (token) {
17                    request = request.clone({
18                        setHeaders: {
19                            Authorization: `Bearer ${token}`,
20                        },
21                    });
22                }
23                return next.handle(request);
24            }),
25        );
26    }
27}

Creating and using a function-based interceptor

To better understand the migration process, we'll first create a simple function-based interceptor:

1import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
2
3export const simpleInterceptorFn: HttpInterceptor = (req: HttpRequest<any>, next: HttpHandler) => {
4  return next.handle(req);
5};

And we can use it as follows:

1@NgModule({
2  providers: [
3    provideHttpClient(
4      withInterceptors([simpleInterceptorFn])
5    ),
6  ],
7})
8export class AppModule {}

or in a standalone application:

1bootstrapApplication(AppComponent, {
2  providers: [
3    provideHttpClient(withInterceptors([simpleInterceptorFn]))
4  ]
5});

That's it! We have created a simple function-based interceptor that we can use in our application.

Migration of the AuthorizationInterceptor to a function-based interceptor

Now that we know how to create and use a function-based interceptor, let's migrate the AuthorizationInterceptor to a function-based interceptor.

Since our interceptor depends on other services, we need to inject these using the inject function.

Here is the updated version of the AuthorizationInterceptor as a function-based interceptor:

1export function authorizationInterceptor(request: HttpRequest<unknown>, next: HttpHandlerFn) {
2    const angularFireAuth = inject(AngularFireAuth);
3
4    if (request.url.indexOf('oauthCallback') > -1) {
5        return next(request);
6    }
7
8    return angularFireAuth.idToken.pipe(
9        mergeMap((token) => {
10            if (token) {
11                request = request.clone({
12                    setHeaders: {
13                        Authorization: `Bearer ${token}`,
14                    },
15                });
16            }
17            return next(request);
18        }),
19    );
20}

We can now use it in the following way:

1@NgModule({
2  providers: [
3    provideHttpClient(withInterceptors([authorizationInterceptor])),
4  ],
5})
6export class AppModule {}

or in a standalone application:

1
2bootstrapApplication(AppComponent, {
3  providers: [
4    provideHttpClient(withInterceptors([authorizationInterceptor]))
5  ]
6});

That's it!

Before vs. After 🚀

| | | | ------ | ------ | |

|
|

Conclusion

The migration from class-based interceptors to function-based interceptors provides numerous benefits. It simplifies the code, makes it more flexible and more maintainable. If your interceptors depend on other services, you can effortlessly use these in the functions creating the interceptors. This provides a clear separation of responsibilities and fosters better testability.

It is recommended to consider the transition to function-based interceptors early in order to benefit from the numerous advantages and to be prepared for future Angular versions.

Inhalt
  • What are the reasons to migrate to function-based interceptors?
  • How is the AuthorizationInterceptor currently set up?
  • How to create and use a function-based interceptor?
  • How to migrate the AuthorizationInterceptor to a function-based interceptor?
  • What are the benefits and conclusions of this migration?
Dennis Hundertmark
Dennis (Softwareentwickler)

Als Frontend-Experte und Angular-Enthusiast gestalte ich Webanwendungen, die Technik und Design gekonnt zusammenführen. Meine Stärke liegt in der Entwicklung benutzerzentrierter Lösungen, die sowohl f... mehr anzeigen

Gitlab
Kiya

... ist unsere engagierte und leidenschaftliche Künstliche Intelligenz und Expertin für Softwareentwicklung. Mit einem unermüdlichen Interesse für technologische Innovationen bringt sie Enthusiasmus u... mehr anzeigen

More about this topic

More from Dennis

Unsere Entwicklungsexpertise

Standort Hannover

newcubator GmbH
Bödekerstraße 22
30161 Hannover

Standort Dortmund

newcubator GmbH
Westenhellweg 85-89
44137 Dortmund