Rxjs Observable: Get HTTP data only for the first subscriber and cached data for the rest

Issue

I’m trying to implement user permissions in an Angular app, but to put it simple, this is the scenario:

Upon loading a MainModule, I make an HTTP request and store the data in the localStorage, so the next time I can retrieve the data from there. This logic is inside an Observable, to which I’m subscribing from several places.

The problem is, if two subscriptions are executed at the same time, two HTTP request will be made before I even have the chance to store the data in the localStorage.

That’s it, but to explain it further…

I’d like to make the HTTP request only once, store the data in the localStorage and emit the value, and from the second subscriber onwards, ignore all this logic if possible and just return the last emitted value.

I tried to use a BehaviorSubject, but then I get the last emitted data when I re-enter the module (i.e. user_A logs out and user_B logs in). The Service I’m using is provided in root, I couldn’t provide it in MainModule because I get DI errors in some guards I have there. I also read about the share operator, but I’m not really sure about how to use it.

UPDATE (adding to @Nugu‘s Answer):

The problem with share was that the piped observable was not completing, so I wrapped a subscription to this.http.get<T> that calls .next(value) and .complete(), inside an Observable, and now it’s working. I also added the condition of localStorage before making the HTTP request.

Also, on every module re-enter, I still got the last emitted value, so I turned the function getSomeData() into a property to always get the same instance of the Observable.

Solution

Use share() operator to share source among multiple subscribers. This will make sure the response is shared among the many subscribers and prevent duplicate HTTP request.

getSomeData(): Observable<any> {
  return this.http.get<any>('/endpoint').pipe(share());
}

You could do an if condition before calling getSomeData() to check if the data is already available in the store.

Answered By – Nugu

Answer Checked By – Katrina (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.