Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add HttpClient Interceptors conditionally in Angular

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);
        }
    });
  }
}
like image 584
Rahul Singh Avatar asked Aug 20 '17 10:08

Rahul Singh


People also ask

Can I have multiple HTTP 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.

Can we bypass interceptor in angular?

So now to bypass the interceptor we can use HttpBackend. For more details about it, please refer to this. When injected, HttpBackend dispatches requests directly to the backend, without going through the interceptor chain. So as per the definition, we can surely use it for our current use case.

How do I add interceptor to APP module?

The interceptor needs to be added to the HTTP_INTERCEPTORS array. This is done by converting the existing HTTP_INTERCEPTORS array using the new class we created. Add this to the ProvidersArray for our application's modules. Any interceptor we want to create needs to implement the HttpInterceptor interface.


2 Answers

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);
}
like image 179
Paulo Guimarães Avatar answered Oct 12 '22 11:10

Paulo Guimarães


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.

like image 34
Johannes Rudolph Avatar answered Oct 12 '22 10:10

Johannes Rudolph