By using interceptors, you can intercept and modify HTTP
requests and responses globally across your entire application.
In this we're going to create a component
, service
and interceptor
In src/app/cancel-repeated-apis/cancel-repeated-apis.html
<div class="h-screen gap-4 flex items-center justify-center bg-black">
<button class="p-3 bg-cyan-400 rounded-lg" (click)="handleClick(1)">
API 1
</button>
<button class="p-3 bg-red-400 rounded-lg" (click)="handleClick(2)">
API 2
</button>
</div>
we're using tailwind
along with it. Nothing serious , just 2 buttons with different colors.
In src/app/cancel-repeated-apis/cancel-repeated-apis.ts
import { Component } from '@angular/core';
import { ApiService } from '../services/api.service';
@Component({
selector: 'app-cancel-repeated-apis',
templateUrl: './cancel-repeated-apis.component.html',
styleUrls: ['./cancel-repeated-apis.component.scss']
})
export class CancelRepeatedApisComponent {
constructor(private apiService: ApiService) { }
// Takes an number and calls a sample api using that
async handleClick(num: number) {
try {
const res = await this.apiService.get(`https://dummyjson.com/products/${num}`)
console.log("🔥 ~ handleClick ~ res:", res)
}
catch (err) {
console.log("🔥 ~ handleClick ~ err:", err)
}
}
}
In /src/app/services/api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) { }
// get request using http , Make sure to import in modules
public get(url: string) {
return this.http.get(url).toPromise();
}
}
In /src/app/interceptors/cancel-same-apis.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse } from '@angular/common/http';
import { Observable, Subject } from 'rxjs';
import { tap, takeUntil } from 'rxjs/operators';
@Injectable()
export class CancelSameApisInterceptor implements HttpInterceptor {
private cache = new Map<string, Subject<void>>();
constructor() { }
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
// Only cancel GET requests
if (request.method !== 'GET') {
return next.handle(request);
}
// if you want to check params as well then use request.urlWithParams.
const url = request.url;
// check if the request is already cached
const cachedResponse = this.cache.get(url);
// cancel any previous requests
if (cachedResponse) {
cachedResponse.next();
}
const cancelRequests$ = new Subject<void>();
// cache the new request , so that we can cancel it if needed.
this.cache.set(url, cancelRequests$);
const newRequest = next.handle(request).pipe(
// cancel the request if a same request comes in.
takeUntil(cancelRequests$),
// complete the subject when the request completes.
tap((event) => {
if (event instanceof HttpResponse) {
this.cache.delete(url);
}
})
);
return newRequest;
}
}
Don't forget to add this interceptor in the provider in app.module.ts
or your respective modules.
providers: [{ provide: HTTP_INTERCEPTORS, useClass: CancelSameApisInterceptor, multi: true }]
We have a map that holds url
as key
and cancelRequest$
as value
.
We always check the cache
before request. If cache
exists we cancel previous requests using the value
which is observable
that is passed in the takeUntil
.
takeUntil
- takeUntil
subscribes and begins mirroring the source Observable
. It also monitors a second Observable, notifier
that you provide. If the notifier emits a value, the output Observable
stops mirroring the source Observable and completes. If the notifier
doesn't emit any value and completes then takeUntil
will pass all values.
🕊 peace
If you are here it means you may have found this blog helpful. Just follow me @shrihari which will motivate to write more. You can make a Buttermilk 🥛. Small support comes a long way!
Subscribe If you want to receive these blogs in your mail from @Medium for free!
Top comments (1)
Nice!