Angular - Interceptor not loading in a lazy loaded module
Asked Answered
L

3

26

I have created an interceptor which appends a token to the authorization header only needed for API calls made within a feature lazy loaded module.

However, I don't think the interceptor is being called as no console.logs are being displayed when within the reports module.

I have read on other questions that this may have something to do with the HTTPClientModule. This HttpClientModule is only ever once initialized in my main app.module.

How do I get an interceptor to work only for a lazy loaded feature module?

auth.interceptor.ts

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs/observable';
import 'rxjs/add/operator/do';

import { AuthService } from './../services/auth/auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private auth: AuthService) {
        console.log('start interceptor');
     }

    intercept(req: HttpRequest<any>, next: HttpHandler) {

        console.log('intercepting');

        const authToken = this.auth.getProfileToken();

        console.log(authToken);

        const authReq = req.clone({
            headers: req.headers.set('Authorization', authToken)
        });

        return next.handle(authReq);

    }

}

reports.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UpperCasePipe } from '@angular/common';
import { DatePipe } from '@angular/common';
import { HTTP_INTERCEPTORS } from '@angular/common/http';

import { ReportsRoutingModule } from './reports-routing.module';

...

import { SharedModule } from './../shared/shared.module';

..

import { AuthInterceptor } from './../core/interceptors/auth.interceptor';

@NgModule({
    imports: [
        CommonModule,
        SharedModule,
        ReportsRoutingModule,
    ],
    declarations: [
        ...
    ],
    entryComponents: [
        ...
    ],
    providers: [DatePipe, UpperCasePipe,
        { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
    ]
})
export class ReportsModule { }

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { SharedModule } from './shared/shared.module';
import { CoreModule } from './core/core.module';
import { HttpClientModule } from '@angular/common/http';
   
@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        AppRoutingModule,
        BrowserAnimationsModule,
        HttpClientModule,
        SharedModule,
        CoreModule.forRoot(),
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }

app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from '../app/core/guard/auth/auth.guard';

const routes: Routes = [
    {
        path: 'reports',
        loadChildren: './reports/reports.module#ReportsModule',
        canActivate: [
            AuthGuard
        ]
    }
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule],
    providers: [AuthGuard]
})
export class AppRoutingModule { }

Lallage answered 16/4, 2018 at 10:36 Comment(16)
I would suggest you move the interceptor to the main module, and code it to only intercept requests to the relevant domain.Waldo
reports is you lazy loaded module ??Tonita
@Waldo are you suggesting that this is not possible? And what do you mean by code it to only intercept requests to the relevant domain?Lallage
@PranayRana thats correct, you can see that from the app-routing.module. Reports is my lazy loaded feature module.Lallage
I don't think it is, no. And I mean in the interceptor you check the request and decide whether or not to do anything with it.Waldo
what are the other places you are registerging AuthInterceptor ? there is only one place right ?Tonita
@PranayRana Im not registering it anywhere else, i only need it for the reports module.Lallage
@Waldo This would be a hack right? To add in globally and check every request to see if it needs modifying in a certian way. Like mentioned i only need this for the reports module. I wouldint even know where to begin to determine if the request came from the reports module or not.Lallage
No, that would be exactly how you're supposed to do it. Even if you only need it for some requests, interceptors are invoked for all requests. The other method for conditional interception is here: https://mcmap.net/q/193287/-how-to-make-an-angular-module-to-ignore-http-interceptor-added-in-a-core-module/3001761.Waldo
@Waldo i think in this case its more difficult to determine what should be ignored.Lallage
Well you'll need to do it somewhere. How do you know which requests should be authenticated? There must be some logic you could encode. But regardless the point is that, as far as I'm aware, there's no way you could have an interceptor that only applies to requests made from a certain module, and all interceptors must be available for injection when the client is created so they can't be lazily loaded.Waldo
The method you mentioned in the stackoverflow thread would require me to add an ignoreintercepter in the headers of all the http requests i make in my app with only 1 request not ignoring the interceptor. I would like to avoid doing that if possible. Thats fine, i believe this is still a valid use case. I will wait to see if anyone else has any input on this. @jonrsharpe.Lallage
Well then do it the other way, have an apply header rather than a skip header. But the validity of your use case is irrelevant, because you can't do it this way. It seems pointless to discuss this further.Waldo
Let us continue this discussion in chat.Lallage
@Lallage Do you use --aot when using ng serve? I think I had some trouble with lazyloading modules without aotTarge
@Lallage Did you get this working in a lazy loaded module?Decolonize
G
28

The HTTP_INTERCEPTORS provider token is reset when a lazy loaded module imports another module which imports the HttpClientModule by itself.

So HttpClientModule can be included in your application module, and is only necessary once.

https://angular.io/guide/http#setup-installing-the-module

Getraer answered 20/5, 2020 at 13:12 Comment(3)
The HttpClientModule SHOULD, and SHOULD ONLY be included in the application module for most use cases.Adulteration
I have used HttpClientModule many times. When I fixed my mistake, the problem disappeared.Holdback
How is this answers the question? The OP asked how to make the http interceptor registered by a lazy-loaded feature module work.Reduplication
E
6

Every time a module loads in lazy loaded module a new instance of the HttpClient service is injected in the module that has not been configured to use the interceptor configured in the AppModule. So add interceptors at module level instead of application level.

Entablement answered 9/8, 2020 at 8:15 Comment(0)
V
-4

Import HttpClientModule into your lazy (reports.module.ts) loaded module, then the interceptor will trigger:

...
@NgModule({
    imports: [
        CommonModule,
        SharedModule,
        ReportsRoutingModule,
        HttpClientModule,
    ],
...
Variolite answered 15/1, 2021 at 8:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.