How to add HttpClient Interceptors conditionally in Angular
Asked Answered
B

2

14

Recently I have been using Interceptors with Angular HttpClient.

I add headers corresponding to some HTTP GET methods and for some I do not need those headers.

How can I tell my interceptor to conditionally add interceptors to only those methods? I can even split up services like one service for headers and one without headers or one for different headers and one for different.

NgModule providers

{
  provide: HTTP_INTERCEPTORS,
  useClass: AuthInterceptor,
  multi: true,
},{
  provide: HTTP_INTERCEPTORS,
  useClass: AngularInterceptor,
  multi: true,
}

MyInterceptors

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const authReq = req.clone({headers: req.headers.set('X-Auth-Token', "-------------------------")});
    return next.handle(authReq);

  }
}


@Injectable()
export class AngularInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).do(event => {}, err => {
        if(err instanceof HttpErrorResponse){
            console.log("Error Caught By Interceptor");
            //Observable.throw(err);
        }
    });
  }
}
Blindage answered 20/8, 2017 at 10:58 Comment(13)
That logic, which requests the interceptor should add headers to, should be in the interceptor.Strepphon
@Strepphon that is being called internally when i am implementing http interceptor along with httpclient.Blindage
I'm not sure what your point is; I know how the new interceptors work (I've written about them). What I'm saying is that the interceptor itself should contain the logic specifying which requests it needs to add the headers to, the intercept method is called for every request, by design.Strepphon
@Strepphon my bad i couldn't understand your statement then. So it will be like adding a bunch of if else of switch to check the req and adding the headers right?Blindage
Yes, precisely. That way everything else can just make the request without worrying about whether or not the header is or should be added.Strepphon
Hmm there could have been a flag of some sorts its not the most clean way i guess do you agree ?. Also any way to combine two interceptors as i wrote i have two one for error log and one for headers can i add them bothBlindage
No, I don't agree; where would the flag come from, where the calls are made? In that case why bother with the interceptor? Why would you want that logic spread out around the rest of the application? And as far as I know that's the only way to add two interceptors in the same module.Strepphon
Thanks. The flag can be passed as an additional field in the get of httpclient as a Key value pair stating that this is eligible for interception and this is not sort of?. Thanks a tonBlindage
Yes, I understand what you're suggesting, but I don't understand why you think that's cleaner. Imagine you have three methods making calls to the same endpoint, which doesn't require the header. Now the requirements change and the endpoint does require the header. Do you want to: 1. change the flag value in all three methods (or one, or two, depending on whether you forget any); or 2. make a single change in the interceptor? The ideal interceptor is self-contained and completely transparent.Strepphon
I get it but completely depends upon the implementation. It can be implented as if no flag is specified it will always go through the interceptor and if a flag is specified if will omit it . Thanks for the healthy discussion.Blindage
Nope, thanks, had enough discussion; do whichever you'd like.Strepphon
This issue has been discussed here: github.com/angular/angular/issues/20203Oospore
This could be a possible duplicate of #46469849. Please check this out.Decagram
A
3

I know it is too late however, we still do not have any solution from Angular. An easy workaround at the moment is to create a BehaviorSubject and activate the Interceptor according to the value it. With this, you are able to handle specifics HTTP requests the must use your Interceptors:

yourService.service.ts

public interceptorTwo = new BehaviorSubject<boolean>(null);

someHttpmethod() {
   this.interceptorTwo.next(true);

   // Add your CODE http
   this.myHttp.post<any>('someUrl', data).finally(() => this.interceptorTwo.next(null));
}

yourInterceptorTwo.service.ts

const setAuth = this.yourService.interceptorTwo.value;
if (!setAuth) {
  return next.handle(req);
}
Azole answered 31/12, 2020 at 12:10 Comment(0)
N
1

Note: I haven't tried this approach myself yet but have played with the idea because we are looking at a similar problem.

If we had very simple requirements, it would be trivial to add logic in a general purpose interceptor and just decide based on URL/Method which kind of interception to perform. However, our angular app needs to call a variety of 1st party micro-services and 3rd party APIs with different requirements for interceptors. This is effectively a superset of your requirements.

One idea to implement this is to extend HttpClient for each API/Service that we need to call and set up a custom injection token for the interceptor chain. You can see how angular registers the default HttpClient here:

 providers: [
    HttpClient,
    // HttpHandler is the backend + interceptors and is constructed
    // using the interceptingHandler factory function.
    {
      provide: HttpHandler,
      useFactory: interceptingHandler,
      deps: [HttpBackend, [new Optional(), new Inject(HTTP_INTERCEPTORS)]],
    },

The interceptingHandler function is even exported as ɵinterceptingHandler. I agree this looks a little weird, not sure why it has that export name.

Anyawy, to use a custom HttpClients you can probably:

export const MY_HTTP_INTERCEPTORS = new InjectionToken<HttpInterceptor[]>('MY_HTTP_INTERCEPTORS');

...
 providers: [
    MyHttpClient,
    {
      provide: MyHttpHandler,
      useFactory: interceptingHandler,
      deps: [HttpBackend, [new Optional(), new Inject(MY_HTTP_INTERCEPTORS)]],
    },

And make sure that MyHttpClient requires a MyHttpHandler in its constructor.

Natterjack answered 28/9, 2017 at 9:1 Comment(2)
thanks for taking time out for this answer, i am still confused about this concept , can you just brief about this in a bit more detailBlindage
that weird name indicates Angular internal code: ɵ (Theta-like) symbol in Angular 2+ source codeLocomotive

© 2022 - 2024 — McMap. All rights reserved.