How to Create a Functional Interceptor in Angular
Tags: angular, withinterceptors, providehttpclient, interceptors
Published: 2023-10-04 00:08:14

---
title: How to Create a Functional Interceptor in Angular
published: true
date: 2023-10-03 21:21:20 UTC
tags: angular,withinterceptors,providehttpclient,interceptors
canonical_url: https://medium.com/@seanhaddock_60973/how-to-create-a-functional-interceptor-in-angular-c2302cc67a90
---

![](https://cdn-images-1.medium.com/max/1024/0*r3zV_CHyPnsxpvdP)
_Photo by Chris Moore on Unsplash_

Angular is moving towards _functional_ interceptors, rather than class-based ones (the same is true of guards). Note this statement in the docs:

> _Prefer…functional interceptors instead, as support for DI-provided interceptors may be phased out in a later release._

What is the difference between a class-based interceptor and a functional one? That is what we are going to explore in this post.

I am going to compare and contrast class-based and functional interceptors in this post, but feel free to skip straight to the functional implementation if that is all you are interested in.

### The Interceptor

#### Class-Based Version

A simple class-based interceptor that adds an Authorization header to all HTTP requests would look something like this:

```
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    const clonedRequest = request.clone({
      setHeaders: {
        Authorization: 'Bearer [the token]',
      },
    });
    return next.handle(clonedRequest);
  }
}
```

The interceptor is just a class that implements the HttpInterceptor interface and participates in dependency injection. The intercept method is the only method implemented and it takes the intercepted request and the next handler, which allows the request to be passed on through the pipeline.

This interceptor is simply cloning the request and setting an Authorization header with a _fake_ Bearer token. It then hands the request off to the next handler (if you want to see a more realistic example of adding an Authorization header you can look at my previous [post](https://dev.to/seanbh/how-to-add-a-bearer-token-to-api-calls-when-using-ngrx-4jhh)).

#### Functional Version

A functional version of this simple interceptor would look like this:

```
import {
  HttpRequest,
  HttpInterceptorFn,
  HttpHandlerFn,
  HttpEvent,
} from '@angular/common/http';
import { Observable } from 'rxjs';

export const authInterceptor: HttpInterceptorFn = (
  request: HttpRequest<unknown>,
  next: HttpHandlerFn
): Observable<HttpEvent<unknown>> => {
  const clonedRequest = request.clone({
    setHeaders: {
      Authorization: 'Bearer [the token]',
    },
  });
  return next(clonedRequest);
};
```

What changes do we see?

- Obviously, the biggest change is that we’ve made the interceptor a constant _function_ (of type HttpInterceptorFn) rather than an injectable _class — _hence the interceptor is now functional rather than class-based.
- The function still takes the same request parameter, but the next handler is now a _function_ rather than a _class_. As such, there is no handle method on next — rather we just invoke next() and pass in the cloned request.

Here are the differences side by side:

![](https://cdn-images-1.medium.com/max/1024/1*eKAziBNXf1RWr9oPAdn60g.png)
_The code difference between the class-based and functional interceptors_

### Providing the Interceptor

The differences in the interceptor are pretty minimal in my opinion. What may be a little more challenging at first is understanding the shift in how we _provide_ the interceptor.

#### Class-Based

We provide a class-based interceptor in the app module like this:

```
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
...
...
imports: [    
    HttpClientModule,
...
...
providers: [
  { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
],
```

Notice that I’ve included the import of the HttpClientModule, not because it is required for the interceptor but because it is required to actually make HTTP requests — or at least it used to be. The way we are going to provide the new functional interceptor also changes the way we gain access to HttpClient.

Note that there is a backwards compatible [way](https://angular.io/api/common/http/withInterceptorsFromDi) to still use the HttpClientModule with a functional interceptor, but I wouldn’t recommend it unless you just need it for a temporary solution until you’re able to fully migrate.

#### Functional

As part of the shift to standalone, Angular now has so-called standalone APIs that allow for building an application without modules. So, when we provide our new functional interceptor, we are going to remove the HttpClientModule completely, and use the standalone API to provide both the interceptor _and_ HttpClient:

```
// HttpClientModule was removed from imports

providers: [provideHttpClient(withInterceptors([authInterceptor]))],
```

The provideHttpClient function is all we need to make HttpClient available in the application. We pass in the withInterceptors function to provide authInterceptor at the same time.

Here’s the diff between the module/class and standalone/functional approaches:

![](https://cdn-images-1.medium.com/max/1024/1*-4viUjiW70IWIhpZWNJLTA.png)
_The code difference between the module/class and standalone/functional approaches_

That’s it! I hope you found this useful.

If you want to see how to unit test the functional interceptor we implemented here, check out this [post](https://medium.com/@seanhaddock_60973/how-to-test-a-functional-interceptor-in-angular-6c8095c1fb7d).

### Bibliography

- [Angular — provideHttpClient](https://angular.io/api/common/http/provideHttpClient)
- [Angular — withInterceptors](https://angular.io/api/common/http/withInterceptors)
- [Angular — withInterceptorsFromDi](https://angular.io/api/common/http/withInterceptorsFromDi#description)
- [Angular — HttpInterceptorFn](https://angular.io/api/common/http/HttpInterceptorFn)