When working with Angular interceptors, there are times we want to configure them based on the context of the application. So, if we want to export the interceptor as a library, we want to be able to configure it in the application that uses it.
In order to better understand it, let’s create a RetryInterceptor
that retries failed requests.
We want to be able to configure the number of retries and the delay between retries. For this we will use the retry operator from RxJS 😎.
Create the interceptor
We will start by creating the interceptor itself. We will create a new file called retry.interceptor.ts
and add the following code to it:
import { Injectable } from '@angular/core';
import { HttpHandler, HttpInterceptor, HttpRequest, } from '@angular/common/http';
import { retry, RetryConfig } from 'rxjs/operators';
@Injectable()
export class RetryInterceptor implements HttpInterceptor {
private retryConfig: RetryConfig = { count: 3, delay: 1000 };
intercept(request: HttpRequest<unknown>, next: HttpHandler) {
return next.handle(request).pipe(retry(this.retryConfig));
}
}
We can see that the interceptor is very simple. It has a retryConfig
property that is used by the retry
operator. The retry
operator will retry the request count
times, with a delay of delay
milliseconds between each retry.
Register the interceptor
Now that we have the interceptor, we need to register it. Before we do that, let’s create a provider object for it:
import { Provider } from '@angular/core';
export const RetryInterceptorProvider: Provider = {
provide: HTTP_INTERCEPTORS,
useClass: RetryInterceptor,
multi: true,
};
We can now register it in the providers
array of the AppModule
:
@NgModule({
// … other properties
imports: [
// … other modules
HttpClientModule,
],
providers: [
RetryInterceptorProvider
],
})
export class AppModule {}
Configure the interceptor
Now, if we want our interceptor to be reusable, we need to move the configuration out of the interceptor itself in order to be able to configure it in the application that uses it. We will do that by creating a new injection token
for the retryConfig
property:
import { InjectionToken } from '@angular/core';
export const RETRY_INTERCEPTOR_CONFIG = new InjectionToken<RetryConfig>(
'retryConfig',
{
providedIn: 'root',
factory: () => {
return { count: 3, delay: 1000 } as RetryConfig;
},
}
);
As we can see it is provided in the root injector, and it has a default value of { count: 3, delay: 1000 }
.
Now we can use this injection token in the interceptor itself:
export class RetryInterceptor implements HttpInterceptor {
- private retryConfig: RetryConfig = { count: 3, delay: 1000 };
+ private retryConfig = inject(RETRY_INTERCEPTOR_CONFIG);
// ... rest of the code
}
We have replaced the retryConfig
property with the value of the RETRY_INTERCEPTOR_CONFIG
injection token.
Now, we can configure the interceptor in the AppModule
:
@NgModule({
providers: [
RetryInterceptorProvider,
+ {
+ provide: RETRY_INTERCEPTOR_CONFIG,
+ useValue: { count: 5, delay: 2000 },
+ },
],
})
export class AppModule {}
We have provided a new value for the RETRY_INTERCEPTOR_CONFIG
injection token. This value will be used by the interceptor instead of the default value.
And that’s it 🎉! We have created a configurable interceptor that can be configured in the application that uses it.
You can play with it here: Stackblitz project 🕹️
As we can see, just to make an interceptor configurable we had to do a lot of work. We had to create a new injection token, register it in the AppModule, and then use it in the interceptor itself. This is a lot of work for such a simple task.
How to make this process easier?
Convert the class based interceptor to a function based interceptor.
Read more about it here 👇:
Migrate Angular Interceptors to function based interceptors 🏃♂️
Thanks for reading!
If this article was interesting and useful to you, and you want to learn more about Angular, support me by buying me a coffee ☕️ or follow me on X (formerly Twitter) @Enea_Jahollari where I tweet and blog a lot about Angular
latest news, signals, videos, podcasts, updates, RFCs, pull requests and so much more. 💎