Search code examples
angularrxjsrxjs6rxjs-pipeable-operators

Is there a way to cache multiple http requests rxjs with shareReplay


I'm trying to cache requests which we get from multiple objects which can have the same url as array something like this

    const a = { urls: ['foo', 'bar'] };
    const b = { urls: ['bar', 'other'] };

I don't want to make a new request once I'm iterating through b urls if a url bar has been requested

I've tried this method which is not working for obvious reasons that logic is not complete

    private allUrls = [];  
    private allUrls$: Observable<{ "...someproperties"; url: string }> =  
        new Observable();
    private api$ = this.allUrls$.pipe(
        mergeMap(() => this.allUrls$),
        shareReplay(1)
    );

    fetchRequest(urls: string[]) {
        urls.map((url) => {
            if (!this.allUrls.includes(url)) {
                this.allUrls$.pipe(mergeMap(() => this.cacheUrl(url)));
            }
        });

        return this.api$.pipe(
            map((response) => {
                return response.filter((r) => urls.includes(r.url));
        })
    );
  }

Solution

  • If I am not wrong you are searching solution like this. Please check my comments carefully.

    export class App {
      constructor(private http: HttpClient) {}
      // This is the chache
      private urlCache: Record<string, string[]> = {};
      onRequest(size: string) {
        // in your case you must return this observable from 
        // your function. Here we constructing url's which are
        // different only by their size parameter. We are doing 
        // this because need to test the implementation somehow ...
        of(`https://random-data-api.com/api/v2/users?size=${size}`)
          .pipe(
            concatMap((requestUrl: string) =>
              iif(
                () => typeof this.urlCache[requestUrl] !== 'undefined',
                of(this.urlCache[requestUrl]).pipe(
                  tap((users) => {
                    console.log(`This request url was cached. We are geting this response from cache.`, users);
                  })
                ),
                this.http.get<{ first_name: string }[]>(requestUrl).pipe(
                  map((users) => users.map((user) => user.first_name)),
                  tap((users) => {
                    this.urlCache[requestUrl] = users.slice();
                    console.log(`This request url was not cached. We are geting this response from the server.`, users);
                  })
                )
              )
            )
          )
          .subscribe((value) => {
            // This is the subscribed observer. 
            console.log(`This is the data which we get in subsbibed observer`, value);
          });
      }
    }
    

    Here you can see working stackblitz url. https://stackblitz.com/edit/angular-eallsn?file=src/main.ts