5

I'm using HttpInterceptor api of Angular's HttpClientModule and now stuck with a situation. Here is my use-case.

In my application, if any service makes an http call, I want to make another silent http call before it, and want to store it's result locally. Once the silent call is completed, then only I'll proceed with the service's http call and will return its result.

Here is what I'm doing. (Using HttpInterceptor)

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.url.match(/api\//)) { // api call
           http.post('/auth/silentCall', {user: 123}).subscribe(
                     (data) => {
                        console.log(data);
                        const clone = req.clone({ setHeaders: { 'Authorization ': tokenService.getToken() } });
                        return  next.handle(clone).do((event: HttpEvent<any>) => {
                            if (event instanceof HttpResponse) {
                                console.log('Service's call response');
                            }
                        }, (err: any) => {
                            if (err instanceof HttpErrorResponse) {
                                console.log('Network call err', err);
                            }
                        });
                     },
                     (err) => {
                        if (err instanceof HttpErrorResponse) {
                           return Observable.throw(err); 
                        }
                 );
                } else {
        console.log('Not an api call..It's an auth call');
       return next.handle(req); // call original auth request.
    }
}

Now, problem with the above code is, it is executing internal silent call successfully, but never calls the original api call after that. So the service keeps waiting forever.

miiiii
  • 1,580
  • 1
  • 16
  • 29

2 Answers2

7

Updated: Added a working plunkr. https://plnkr.co/edit/WFecj8fFZ6z4G6mpLSCr?p=preview

Take note of the sequence that the calls are being made and the headers that are being added using your browser's dev tools.

Also note that the below solution is using RxJS lettable operators instead of the standard operators (which shouldn't have any different behavior. Adding this note in case the code doesn't compile)


The cause of the problem is the fact that the intercept method is never returning a handle in the case that the call matches /api.

Update your code to something similar to the following

intercept(req: HttpRequest<any>, next: HttpHandler):Observable<HttpEvent<any>> {
    if (req.url.match(/api\//)) { // api call
           return http.post('/auth/silentCall', {user: 123}).pipe(switchMap((response) => {
               console.log("Service's call response");
                    
               let clone = req.clone({ setHeaders: { 'Authorization ': tokenService.getToken() } });
               return  next.handle(clone);
           }), catchError((err) => {
               if(err instanceof HttpErrorResponse) {
                   console.log('Your logging here...');
                   let clone = req.clone({ setHeaders: { 'Authorization ': tokenService.getToken() } });
                   return  next.handle(clone);
               }

               return Observable.throw(err); 
           }));
    } else {
       return next.handle(req); // call original auth request.
    }
}

Note that the response of the http.post is being flatmaped to return the observable sequence returned by the next.handle() method or to thrown a terminated observable with Observable.throw().

Also note that the if condition has been removed since if the api call fails, the catch block is called (or the error handler function, in case of subscribe)

ssuperczynski
  • 3,190
  • 3
  • 44
  • 61
JeanPaul A.
  • 3,613
  • 1
  • 20
  • 29
  • No it didn't work.. Got no error and no improvement, while debugging result is same... It does the silent call but never proceed to call actual service call. – miiiii Dec 16 '17 at 08:31
  • You must be doing something wrong. I've updated it with a working plunkr. note that in order for your approach to work, you need to use the **deprecated** Http service. You **cannot** do a call using the HttpClient service within the HttpInterceptor since it would create a cycling dependency. – JeanPaul A. Dec 18 '17 at 12:31
  • Thanks Jean, but why not to go with the latest version i.e. HttpClient ? You can use reflective injection to avoid cyclic dependency. Can you do it with new version? Bcoz, I used reflective injection and it works for the silent call which I initiated within the interceptor. – miiiii Dec 18 '17 at 12:40
  • Thanks Manoj for pointing that out. I wasn't aware of that. :) Plunkr have been updated to use HttpClient within the interceptor. – JeanPaul A. Dec 18 '17 at 13:55
  • Hey Jean, I already got the solution, and is perfectly meets my requirement . Your plunkr example hepled a lot. Thanks. – miiiii Dec 18 '17 at 14:38
  • I'll soon post my answer, just to help, in case anyone facing same situation now or in future. :) thanks again @Jean !! – miiiii Dec 18 '17 at 14:54
  • `flatmaped` made my day - after spending a few hours with it. Thanks a lot! – Nicolae Olariu Nov 20 '18 at 18:57
0

You are not returning the observable inside if. Try this

return http.post('/auth/silentCall', {user: 123}).subscribe(
Muthukumar
  • 8,679
  • 17
  • 61
  • 86
  • If i return it on silentCall, I can't write return statement on actual service call response, and I did so, still the call never goes to execute the `next.handle(clone)`.. Sorry Sir, but got no improvement. – miiiii Dec 16 '17 at 08:42