DEV Community

Shrihari Mohan
Shrihari Mohan

Posted on • Edited on

4

Cancel repeated requests in Angular with interceptors

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>


Enter fullscreen mode Exit fullscreen mode

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



Enter fullscreen mode Exit fullscreen mode

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

}


Enter fullscreen mode Exit fullscreen mode

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;

  }
}


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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 - takeUntilsubscribes 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!

More things from me

AWS GenAI LIVE image

How is generative AI increasing efficiency?

Join AWS GenAI LIVE! to find out how gen AI is reshaping productivity, streamlining processes, and driving innovation.

Learn more

Top comments (1)

Collapse
 
raviagheda profile image
Ravi Agheda

Nice!

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay