DEV Community

Cover image for How to Remove Repeated API Calls Like a Pro with Just RxJs and Leaving the Content Always Available
Renan Ferro
Renan Ferro

Posted on

How to Remove Repeated API Calls Like a Pro with Just RxJs and Leaving the Content Always Available

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:

Image description

⛳️ The Networking:

Image description

And you go to the Market List page:

⛳️ The Market List page:

Image description

⛳️ The Networking:

If you look in the Networking tab, now we have the marketList API call, for now it's ok the process!

Image description

And after a few minutes, you decide to go to the About page:

⛳️ The About page:

Image description

⛳️ The Networking:

Image description

Aaand after that, you decide to go back to the Market List page (yes, again):

⛳️ The Market List page:

Image description

⛳️ The Networking:

Image description

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>,
}


Enter fullscreen mode Exit fullscreen mode

🧩 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
  ) { }

  ....
}


Enter fullscreen mode Exit fullscreen mode

🧩 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),
      )
  }

  ....
}


Enter fullscreen mode Exit fullscreen mode

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,
    });
  }

  ....
}


Enter fullscreen mode Exit fullscreen mode

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,
    });
  }
}


Enter fullscreen mode Exit fullscreen mode

🎯 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:

Image description

⛳️ Navigated to the About page:

Image description

⛳️ Navigated to the Market List page:

Image description

⛳️ Networking at the end of all navigation:

Image description


🎯 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:

⭐️ Star Angular CRUD on GitHub ⭐️

Top comments (1)

Collapse
 
jangelodev profile image
João Angelo

Hi, Renan Ferro,
Excellent article !
Thanks for sharing