I'm trying to figure out how to best solve a race condition in my app in the simplest way possible.
I have a route with two resolvers. The resolvers are:
GetBooksResolver
GetAuthorsResolver
Now, both Authors and Books have a type Genre
that needs to be merged in.
Thus in both of the resolvers, you have a forkJoin:
// GetBooksResolver:
forkJoin(this.http.get('api/genres'), this.http.get('api/books'))
.pipe(map(data => //merge datasets));
//GetAuthorsResolver
forkJoin(this.http.get('api/genres'), this.http.get('api/authors'))
.pipe(map(data => //merge datasets));
I have a simple HTTP caching service that does correctly prevent the HTTP requests from firing again, but the initial race condition is still there.
As a result, you see two different api/genre
calls
Any way to set up a caching interceptor so that this doesn't happen?
In an angular application the better way to achieve the caching is to use HTTP interceptors. As their name suggests it allows us to intercept HTTP messages, with the help of which we can change the HTTP requests or the HTTP responses. Hence it a better option for caching the HTTP requests.
This is called caching. In HTTP, not all requests are cached. POST, PUT, and DELETE requests are not cached because they change the data in the server. POST and PUT add data to the server while DELETE removes data from the server. So we need to process them every time they’re requested without caching them. GET requests can be cached.
Caching HTTP requests helps to optimize your application. Imagine requesting a piece of data from the server every time a request is placed, even if the data has never changed over time.
Though angular has so many things defined, still there are some things that you have to figure out on your own. “There are only two hard things in Computer Science: cache invalidation and naming things.”, Caching things is very easy but clearing the cache is difficult.
As already suggested in the comments you can create a method that will call the service return a replay Observable
like this:
public getGenres(): Observable<Genre> {
return this.httpClient.get('api/genres').pipe(
shareReplay(1)
);
}
Then you call this method to get the replay Observable
and use it in both forkJoin methods:
const genres$ = this.getGenres();
// GetBooksResolver:
forkJoin(genres$, this.http.get('api/books'))
.pipe(map(data => //merge datasets));
//GetAuthorsResolver
forkJoin(genres$, this.http.get('api/authors'))
.pipe(map(data => //merge datasets));
I have also created a working StackBlitz sample so you can see it in action.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With