Angular 15: interceptor as a function
Tags: angular, webdev, javascript, news
Published: 2023-01-11 08:57:11

## 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

```typescript
bootstrapApplication(AppComponent, {
  providers: [ importProvidersFrom(HttpClientModule) ]
}).catch(console.error);
```

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.

```typescript
bootstrapApplication(AppComponent, {
  providers: [ provideHttpClient() ]
}).catch(console.error);
```

## 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.

```typescript
@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());
  }
}
```

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

```typescript
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()))
}
```

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.

```typescript
bootstrapApplication(AppComponent, {
  providers: [ provideHttpClient(
    withInterceptors([AuthorizationInterceptor])) 
  ]
}).catch(console.error);
```

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](https://angular.io/api/common/http/provideHttpClient).

## 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:

```typescript
{ provide: HTTP_INTERCEPTORS,
  useClass: AuthorizationInterceptorDI
  multi: true
}
```

to the httpClient istance.


```typescript
bootstrapApplication(AppComponent, {
  providers: [ provideHttpClient(
    withInterceptorsFromDi()) 
  ]
}).catch(console.error);
```

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.