Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call another http api (without Intercepting) before actual http call is made in Angular's HttpInterceptor

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.

like image 440
miiiii Avatar asked Dec 15 '17 14:12

miiiii


People also ask

What is HttpInterceptor?

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. Keep in mind that the interceptor wants only HTTP requests.

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.

How do you stop the interceptor?

Disable Interceptors Programmatically To disable interceptors in code, use the sessionService. executeInLocalViewWithParams method. It is an implementation of a template method pattern and takes a map of attributes that are set in a session before execution of the provided callback method, and reverted afterwards.


1 Answers

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)

like image 194
JeanPaul A. Avatar answered Nov 06 '22 22:11

JeanPaul A.