Search code examples
angularasynchronousindexeddbangular-http-interceptors

Angular HttpInterceptor - Handle with async response


I am writing Angular application that uses IndexedDB to cache data.

Whenever the application is about to do specific http call to the server I would like to retrieve this data from the IndexedDB and enrich or replace the response from the server.

The problem is the that retrieving data from IndexedDB is Asynchronous operation that returns Observable and I am unable to return the modified data back to the calling service.

The Interceptor looks like this:

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

  return next.handle(req).map((event) => {
    if (event instanceof HttpResponse) {
      console.log("before cacheResponseProccess");

      const val: Observable<HttpEvent<any>> = this.angularCache.cacheResponseProccess(event);

      val.subscribe(x => {
        console.log('Return modified response is:');
        console.log(x);
        return x;
      });
    }
  }).catch((error, caught) => {
    return Observable.throw(error);
  });
}

Please see sample of the issue at https://stackblitz.com/edit/angular-owqgb6


Solution

  • You need to return things in map operator(returning values in callbacks of asynchronous won't really return them to outside function). Also, as you are retrieving asynchronous result to replace original HttpResponse, you can change map to mergeMap operator and return a Observable in it.

    Try with below code example:

    return next.handle(req).mergeMap((event) => {   // use mergeMap instead of map
      return new Observable(ob => {                 // return new Observable to retrieve asynchronous data
        if (event instanceof HttpResponse) {
          console.log("before cacheResponseProccess");
    
          const val: Observable<HttpEvent<any>> = this.angularCache.cacheResponseProccess(event);
    
          val.subscribe(x => {
            console.log('Return modified response is:', x);
            ob.next(x);         // return modified result
          });
        }
      });
    }).catch((error, caught) => {
      return Observable.throw(error);
    });
    

    Fixed demo.