Angular: How to auto unsubscribe requests API to handle duplicate requests.

Afif Alfiano
5 min readFeb 24, 2023

--

Make sure your product doesn’t have a duplicate request endpoint.

https://www.pexels.com/photo/sliced-lemon-on-gray-chopping-board-952484/
https://www.pexels.com/photo/sliced-lemon-on-gray-chopping-board-952484/

Have you tried when you are visiting some page and hit some endpoint, but the network list is have multiple requests with the same endpoint and or query param? If the duplicate is only one or two, maybe it is no problem.

But, let’s imagine what about a ten, a thousand, a hundred(worst case) duplicate hit endpoint. For example: We have a component select that is able to search data. When we search some data by typing some keyword and every single word will request an endpoint to find the data. It will be a lot of request list on the tab network of the browser.

Actually, we can use throttle and debounceTime from rxjs to handle this thing. But what about if I don’t want to use it and I just want from angular itself, without a third party.

The project will be like this

Demo Project

First of all, Let’s initiate the project and for this tutorial, I use angular version 15. I also use open API pokemon

Open file app.module.ts and add HTTP client module and forms module

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import {HttpClientModule} from '@angular/common/http'
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

After that, update app.component.html

<div class="container">
<h1>Pokemon</h1>
<div>
<label for="">Limit: </label>
<input type="text" [(ngModel)]="limit">
</div>
<div class="data">
<p>
{{dataPokemon | json}}
</p>
</div>
<div class="action">
<button (click)="requestApi()" class="generate" type="button" [disabled]="+limit === 0">Generate API</button>
<button (click)="resetData()" class="reset" type="button" [disabled]="dataPokemon?.length === 0">Clear</button>
</div>
</div>
  • The two-way data binding is how to make dynamic variable limit by the input that used to request hit endpoint.
  • Pipe json it to convert data json to stringify
  • Button Generate API is a button to generate duplicate api
  • Button Clear is a button to clear the state data of pokemon.

Also, add some styling and update the file app.component.scss

.container {
width: 100%;
display: flex;
justify-content: center;
flex-direction: column;
h1 {
text-align: center;
}

.data {
height: 200px;
min-height: 200px;
overflow: auto;
margin: 10px 0;
}

.action {
width: 100%;
display: flex;
justify-content: center;
gap: 5px;

button {
width: 200px;
border: 0;
padding: 5px;
color: #fff;
border-radius: 4px;
&.generate {
background-color: maroon;
cursor: pointer;

&:disabled {
background-color: rgb(146, 77, 77);
cursor: not-allowed
}
}
&.reset {
background-color: gray;
cursor: pointer;

&:disabled {
background-color: rgb(203, 203, 203);
cursor:not-allowed
}
}
}
}
}

The next step, update app.component.ts

import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Component } from '@angular/core';
import { Subscription } from 'rxjs';

interface Response {
count?: number;
next?: string | null;
prevous?: string | null;
results?: {name: string, url: string}[];
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'angular-unsubscribe-duplicate-hit-endpoint';
URL = 'https://pokeapi.co/api/v2/pokemon';
dataPokemon?: {name: string, url: string}[] = [];
pokemonSubscribe$!: Subscription;
limit = 10;

constructor(private httpClient: HttpClient) {}

requestApi(): void {
for (let index = 0; index < this.limit; index++) {
if (this.pokemonSubscribe$) {
this.pokemonSubscribe$.unsubscribe();
}
this.doHitEndpoint(this.limit, 0);
}
}

doHitEndpoint(limit: number, offset: number) {
this.pokemonSubscribe$ = this.httpClient.get(this.URL + `?limit=${limit}&offset=${offset}`).subscribe((response: Response) => {
if (response.results) {
this.dataPokemon = response!.results;
}
}, (err: HttpErrorResponse) => {
console.log(err, 'error');
})
}

resetData() {
this.dataPokemon = [];
}
}

Let’s break down the code, one by one.

requestApi(): void {
for (let index = 0; index < this.limit; index++) {
if (this.pokemonSubscribe$) {
this.pokemonSubscribe$.unsubscribe();
}
this.doHitEndpoint(this.limit, 0);
}
}
  • The above function means we will request the same endpoint by limitation. If the limit is 100, so it will hit the endpoint 100 times.
  • In iteration, we will check the subscribe from function doHitEndpoint that is used for hit endpoint (I will explain after this).
  • If the subscribe has the value subscribe, then it will be unsubscribe and run the function until the last iteration.
doHitEndpoint(limit: number, offset: number) {
this.pokemonSubscribe$ = this.httpClient.get(this.URL + `?limit=${limit}&offset=${offset}`).subscribe((response: Response) => {
if (response.results) {
this.dataPokemon = response!.results;
}
}, (err: HttpErrorResponse) => {
console.log(err, 'error');
})
}
  • The function is for request endpoint with HTTP Method GET with the limitation and offset.
  • The reason why we need to assign a variable pokemonSubscribe$ into the request hit endpoint is because we want to check the duplication requests.
  • If any data subscribe on that variable, it will auto unsubscribe.
  • The benefit is we don’t need to wait for all requests to be completed, because only execute the request endpoint until done for the last request or last iteration.

I will show you the problem if you don’t use that method to handle the duplicate endpoint. Although, this is not the only one solution for handling the duplicate request endpoint.

Let’s update first for the function requestApi

  requestApi(): void {
for (let index = 0; index < this.limit; index++) {
// if (this.pokemonSubscribe$) {
// this.pokemonSubscribe$.unsubscribe();
// }
this.doHitEndpoint(this.limit, 0);
}
}
  • It will request the endpoint how much the limitation and ignoring to checking the variable pokemonSubscribe$.

Then, the project will be like this.

Duplicate Endpoint.

Actually, There are many ways to go to Rome. As I mentioned in the second paragraph (not using a third party), I think this way is possible to implement in your project.

But, if you want to another way, you can try to use RxJs, like using throttle, debounceTime and etc. Read more about RxJS.

Oh, I almost forgot, for the project I have pushed on my GitHub account here.

I think that's all about some tips or tricks on how to handle duplicate request endpoints on Angular (not only on angular 15). Hopefully, you can enjoy this tutorial, and if any feedback just gives it to me and I will make it better for the next section. Thank you guys!!!.

References

#Angular #TutorialAngular #Frontend #DuplicateEndpoint

--

--

No responses yet