title: Temporarily caching HTTP responses from parametrised requests using RxJS (and Angular)
body: <p>I would like to cache and expire the HTTP responses from e.g. a GET request with certain params.</p>
  
  <p><strong>An example of a use case:</strong></p>
  
  <p>Suppose I build a service like this:</p>
  
  <pre><code>@Injectable()
  export class ProductService {
  
    constructor(private http: HttpClient) {}
  
    getProduct$(id: string): Observable&lt;Product&gt; {
      return this.http.get&lt;Product&gt;(`${API_URL}/${id}`);
    }
  
    getProductA$(id: string): Observable&lt;ProductA&gt; {
      return this.getProduct$(id).pipe(
        // bunch of complicated operations here
      };
    }
  
    getProductB$(id: string): Observable&lt;ProductB&gt; {
      return this.getProduct$(id).pipe(
        // bunch of other complicated operations here
      };
    }
  
  }
  </code></pre>
  
  <p>Now for whatever reason, function A is called in component A and function B is called in component B. I know this could be done in another way (such as a top-level smart component getting the HTTP data and passing it through input params), but for whatever reason, the two components are "smart" and they each call a service function.</p>
  
  <p>Both components are loaded on the same page, so two subscriptions happen = two HTTP requests to the same endpoint - even though we know that the result will most likely be the same.</p>
  
  <p>I want to simply cache the response of <code>getProduct$</code>, BUT I also want this cache to expire pretty quickly, because in 2 minutes Margareth from product management is going to change the product price.</p>
  
  <p><strong>What I tried but doesn't work:</strong></p>
  
  <p>Basically, I tried keeping a dictionary of hot observables using shareReplay with a window time of 5s. My assumption was that if the (source) observable completes or the number of subscriptions is 0, then the next subscriber would simply refire the observable, but this does not seem to be the case.</p>
  
  <pre><code>private product$: { [productId: string]: Observable&lt;Product&gt; } = {};
  
  getProduct$(id: string): Observable&lt;Product&gt; {
    if (this.product$[id]) {
      return this.product$[id];
    }
    this.product$[id] = this.http.get&lt;Product&gt;(`${API_URL}/${id}`)
      .pipe(
        shareReplay(1, 5000), // expire after 5s
      )
    );
    return this.product$[id];
  }
  </code></pre>
  
  <p>I thought, I can try to remove the observable from my dictionary on completion using finalize or finally, but unfortunately those are also called on every unsubscribe.</p>
  
  <p>So the solution must be perhaps more complicated.</p>
  
  <p>Any suggestions?</p>