How to restrict number of API calls per interval with RxJs?

Viewed 1273

I'm developing an Angular application. And I use API provided by one of the social networks and it has the restriction of 5 API calls per second only.

The most direct solution is to write custom logic that will count requests and queue them up to the restrictions. So if I'm sending the 6th request to the API within one second, it will be sent in second after the 1st request was sent.

But I want to find some elegant solution if it's possible using RxJs.

For instance, I can set debounseTime for Observable like in the following example. But what I actually get is that I cannot make a few requests in the row with a smaller interval than 200ms between them.

this.searchControl.valueChanges
    .debounceTime(200) // 200ms ~ 5 requests per second 
    .switchMap(search => this.api.searchPeople(search))

Has the RxJs any techniques that can restrict a number of emits per interval and queue them in case requests are being sent too frequently?

2 Answers

If you're interested in more Angular approach, here's an interceptor for Angular 6 and RxJS 6 (based on the original answer):

@Injectable()
export class RequestRateLimitInterceptor implements HttpInterceptor {

  private readonly timeFrame = 1000 /* 1 second time frame */;

  private availableThreads = 10 /* 10 requests per the time frame */;

  private rateLimit$ = new BehaviorSubject(this.availableThreads);

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.rateLimit$.pipe(
      filter(() => this.availableThreads > 0),
      take(1),
      tap(() => this.removeThreads()),
      tap(() => timer(this.timeFrame).subscribe(() => this.addThreads())),
      mergeMap(() => next.handle(req))
    );
  }

  private addThreads(): void {
    this.changeThreads(1);
  }

  private removeThreads(): void {
    this.changeThreads(-1);
  }

  private changeThreads(value: number): void {
    this.rateLimit$.next(this.availableThreads += value);
  }
}
Related