Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6: provide HTTP_INTERCEPTORS for 'root'

With the change from Angular 5 where you provide service in AppModule to Angular 6 where you set 'provideIn' key in @Injectable decorator I have changed all services to use new "provideIn" method. However, exception is my Interceptor Service.

How can I provide HTTP_INTERCEPTORS token for 'root' and use InterceptorService?

this is the Angular 5 way I use atm:

@Injectable()
export class InterceptorService implements HttpInterceptor {
...
}

in AppModule:

providers: [{
  provide: HTTP_INTERCEPTORS,
  useClass: InterceptorService,
  multi: true
}]

But what would be Angular 6 way?

I've tried something like

@Injectable({
  provideIn: 'root',
  useValue: HTTP_INTERCEPTORS,
  deps: [forwardRef(() => InterceptorService)]
})
export class InterceptorService implements HttpInterceptor {
...
}

and a lot of other variants with Injectable but can't seem to figure out how to make it work without writing an object literal directly into providers of a module.

like image 570
Miloš Tomšik Avatar asked May 07 '18 09:05

Miloš Tomšik


People also ask

Can we provide multi interceptors in Angular?

After providing HTTP_INTERCEPTORS we need to inform the class we are going to implement our interceptor into by using useClass. Setting multi to true, makes sure that you can have multiple interceptors in your project.

What is Http_interceptors in Angular?

HTTP_INTERCEPTORSlink A multi-provider token that represents the array of registered HttpInterceptor objects.

What is the use of HTTP interceptor in Angular 6?

HTTP Interceptors is a special type of angular service that we can implement. It's used to apply custom logic to the central point between the client-side and server-side outgoing/incoming HTTP request and response.


1 Answers

A couple things to note here:

1. providedIn: 'root' is a nice feature but it probably wasn't built for you

As @Leon mentioned, this feature is meant to make services more tree shakeable. It is not meant to completely replace using the providers: [] property of a module. It is an option mostly meant for library developers, not as much for application developers.

Imagine this scenario:

You created a service a few months ago and now your app is no longer using it. You know it's not using it because it's your app and you have full knowledge and control over the codebase. What do you do to that service?

A) Make sure it's using providedIn: 'root' so that Angular can tree shake it out of the bundle since you're not using it anymore

B) Delete the service.

My guess is B!

Imagine another scenario:

You are using a 3rd party Angular module from an npm package. That module has 12 difference services you can use in your app to take advantage of its features. Your app doesn't need all those features so you only inject 3 of those service types into your application components or services.

How do you resolve this?

A) Fork the repository so you can remove all the services your app doesn't use so you don't have to include them in your bundle.

B) Ask the project owner to use providedIn: 'root'. If the library author used providedIn: 'root' the services you don't use don't have an impact on your bundle size and they can stay in the npm package/Angular module for other teams to use if they need them.

My guess is B!

2. providedIn: 'root' doesn't work for interceptors

Interceptors are a multi DI token service which means you can provide multiple values for the same DI token. That token is HTTP_INTERCEPTORS. The @Injectable({...}) decorator exposes no api for providing the decorated type for a different token the way the @NgModule({...}) decorator does.

This means you can't tell Angular Anywhere you would normally ask for 'HTTP_INTERCEPTORS' add this service to the set of values to use instead using the @Injectable({...}) decorator.

You can only do this in a @NgModule({...}) decorator.

3. Providing interceptors is order dependent

Interceptors are a pipeline and the order they are provided in matters in determining the order they get access to the request object (to modify or inspect) and the response object (to modify or inspect).

While some interceptors might be order agnostic you still probably want some determinism in that ordering.

So even if providedIn: 'root' worked for interceptors the order they would be provided in would be determined by the resolution order of types during the Angular compile step - probably not what you want.

Instead providing them in the providers: [] array in an @NgModule({...}) decorator means you can explicitly set the order they will be called in.

like image 138
seangwright Avatar answered Nov 15 '22 20:11

seangwright