Now, how are you?! I'm doing good and I hope you are fine too! Today we're going to talk about how we can remove unnecessary/repeated API call's and make your application better and faster than before!
So, let's gooo!
🎯 Understanding the Problem
When we have an application (big or small) with a few pages and some API calls we need to improve the user experience and the application performance!
Now, let's see an example about the problem and how it happens!
🧩 The Problem Example:
So, imagine you're in a website more specify in the home page:
⛳️ The Home page:
⛳️ The Networking:
And you go to the Market List page:
⛳️ The Market List page:
⛳️ The Networking:
If you look in the Networking tab, now we have the marketList API call, for now it's ok the process!
And after a few minutes, you decide to go to the About page:
⛳️ The About page:
⛳️ The Networking:
Aaand after that, you decide to go back to the Market List page (yes, again):
⛳️ The Market List page:
⛳️ The Networking:
Now, we have a little problem! If you look in the Networking tab we have two marketList call's! But, if you remember we opened the Market List page once and when we came back we made the same marketList call!
This can be a problem, because if we think we have a large application with many user acesses, many API Calls, the performance will be poor and the user experience too! Because we'll have unnecessary repeated API calls, as they have already been called once.
We have many options to solve this problem! For example, in this example project I solved using State Management with NGXS, you can see the project and Networking here: Angular CRUD Market List. But we have many other options too, what I would like to show you here is a small solution!
Buuut, we can solve this using RxJs Operators and a small framework, let's see how we can do it!
🎯 The Solution
Now, we know the problem and let's see how we can improve it and turn our application better!
🧩 What we are need:
To do that we'll need to make some things, like below:
- Create a model to Store the API's requests in an array
- Create the marketList observable, listOfAvailableRequests array and the request marketList identifier to store in the array (this is optional)
- Create the structure to make the marketList call api
- Create the structure to save the request if it doesn't exist in the array
- Structure to validate the API's requests already in the array
- Use shareReplay RxJs operator
Now, let's implement it step by step
🧩 Create the Model:
First, we'll create a observables array model, with two parameters, like below:
import {Observable} from "rxjs";
export interface RequestCached{
requestIdentifier: string,
storedObservable: Observable<any>,
}
🧩 Create the martketListRequest observable, listOfAvailableRequests array:
In this example, we'll create some variables to use in your service for the API Request, the list requests and the API identifier (Just to pass for the API url):
export class MarketService {
private martketListRequest$: Observable<Card[]>
private listOfAvailableRequests: RequestCached[] = [];
private readonly marketListIdetifier: string = 'marketList';
constructor(
private _httpClient: HttpClient
) { }
....
}
🧩 Create the structure to do the marketList call api:
Basically here we'll create the request structure and use the shareReplay RxJs operator
import {Observable, shareReplay} from 'rxjs';
export class MarketService {
...
private makeMarketListRequest(): void {
this.marketItem$ = this._httpClient
.get<Card[]>('marketList')
.pipe(
shareReplay(1),
)
}
....
}
You can se more about the shareReplay here
🧩 Create the structure to save the request if it doesn't exist in the array:
A simple structure to save the request in the listOfAvailableRequests array
export class MarketService {
...
private pushNewRequestToStoreList(requestIdentifier: string, requestObservable: Observable<Card[]>): void {
this.listOfAvailableRequests.push({
identifier: requestIdentifier,
storedObservable: requestObservable,
});
}
....
}
And finally, our structure will be like below:
export class MarketService {
private martketListRequest$: Observable<Card[]>
private listOfAvailableRequests: RequestCached[] = [];
private readonly marketListIdetifier: string = 'marketList';
constructor(
private _httpClient: HttpClient
) { }
getMovies(): Observable<Card[]> {
let requestStoredReady: RequestCached | undefined;
if (!this.listOfAvailableRequests.length){
this.makeMarketListRequest();
this.pushNewRequestToStoreList(this.marketListIdetifier, this.martketListRequest$);
} else {
requestStoredReady = this.listOfAvailableRequests.find((requestItemData: RequestCached) => requestItemData.identifier === this.marketListIdetifier);
if (!!requestStoredReady){
this.martketListRequest$ = requestStoredReady.observableCached;
} else {
this.makeMarketListRequest();
this.pushNewRequestToStoreList(this.marketListIdetifier, this.martketListRequest$);
}
}
return this.martketListRequest$;
}
private makeMarketListRequest(): void {
this.martketListRequest$ = this._httpClient
.get<Card[]>('marketList')
.pipe(
tap(response => console.log(response)),
shareReplay(1)
)
}
private pushNewRequestToStoreList(requestIdentifier: string, requestObservable: Observable<Card[]>): void {
this.listOfAvailableRequests.push({
identifier: requestIdentifier,
observableCached: requestObservable,
});
}
}
🎯 Testing
Now, we can go to the home, market list page, about page and go back to the market list page and we will have only a marketList API call, as you can see below:
⛳️ Navigated to the Market List page:
⛳️ Navigated to the About page:
⛳️ Navigated to the Market List page:
⛳️ Networking at the end of all navigation:
🎯 Conclusion
That's can be very useful when we have a big application with a few API calls, as we can the "observables cache" and they will be available to us whenever we want!
You can find, fork and see the project here. I hope you enjoyed it, learned something and that it helps you in some way!
Anything just leave a comment and let's talk!
And if you like it, please, give a start:
Top comments (1)
Hi, Renan Ferro,
Excellent article !
Thanks for sharing