How to Remove Repeated API Calls Like a Pro with Just RxJs and Leaving the Content Always Available
Tags: angular, rxjs, tutorial, frontend
Published: 2024-01-18 17:51:24


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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fnx970pixg33hcoum3o7.png)

#### ⛳️ The Networking:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ze04i7gbszcy61u1wlsx.png)

And you go to the **Market List** page:

#### ⛳️ The Market List page:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jyhvgtk6rk6mst76n0y.png)

#### ⛳️ 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xagldi0surdu31k1grsh.png)

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

#### ⛳️ The About page:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pbky23wzpnz3fxcx8qgb.png)

#### ⛳️ The Networking:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/20fzbuuxwlt15jokfocv.png)

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

#### ⛳️ The Market List page:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dk8hzfdype72jk90sund.png)

#### ⛳️ The Networking:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5bqy64ax98h5i9j3vkn.png)

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](https://angular-crud-renanferro.vercel.app/). 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:

```typescript
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):

```typescript
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

```typescript
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](https://rxjs.dev/api/operators/shareReplay)

### 🧩 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

```typescript
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:

```typescript
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:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n24tdpx2mlczf5mgmeu1.png)

### ⛳️ Navigated to the About page:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gcja8yip8aewydcnca0e.png)

### ⛳️ Navigated to the Market List page:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n24tdpx2mlczf5mgmeu1.png)

### ⛳️ Networking at the end of all navigation:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3a89uheqdwyadzvp5jh.png)

___

## 🎯 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](https://github.com/ferrorenan/angular-crud). 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:

<center>
<a href="https://github.com/ferrorenan/angular-crud" role="button">⭐️ Star Angular CRUD on GitHub ⭐️</a>
</center>