Add queueing to Angular's HttpClient

queue in angular
angular multiple http requests sequentially
rxjs queue
angular 6 chain http requests
forkjoin angular 7 example
forkjoin in angular
nested subscribe angular
chaining observables angular

I have exact same requirement as mentioned in Add queueing to angulars $http service but need implementation in Angular 4.3 or 5 using the HttpInterceptor from @angular/common/http.

I have a very quirky API that can only handle a single request at a time for a particular browser session. Therefore, I need to ensure that every time a request is made in same session, it goes into a queue, and that queue is executed one request at a time, until it is empty.


Solution

@Zlatko has suggested correct approach, although there are few logical and syntax issues in it but I have corrected it pasting below a working code:

import { Injectable } from '@angular/core';
import { Response } from '@angular/http';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject'

export class PendingRequest {
  url: string;
  method: string;
  options: any;
  subscription: Subject<any>;

  constructor(url: string, method: string, options: any, subscription: Subject<any>) {
    this.url = url;
    this.method = method;
    this.options = options;
    this.subscription = subscription;
  }
}

@Injectable()
export class BackendService {
  private requests$ = new Subject<any>();
  private queue: PendingRequest[] = [];

  constructor(private httpClient: HttpClient) {
    this.requests$.subscribe(request => this.execute(request));
  }

  /** Call this method to add your http request to queue */
  invoke(url, method, params, options) {
    return this.addRequestToQueue(url, method, params, options);
  }

  private execute(requestData) {
    //One can enhance below method to fire post/put as well. (somehow .finally is not working for me)
    const req = this.httpClient.get(requestData.url)
      .subscribe(res => {
        const sub = requestData.subscription;
        sub.next(res);
        this.queue.shift();
        this.startNextRequest();
      });
  }

  private addRequestToQueue(url, method, params, options) {
    const sub = new Subject<any>();
    const request = new PendingRequest(url, method, options, sub);

    this.queue.push(request);
    if (this.queue.length === 1) {
      this.startNextRequest();
    }
    return sub;
  }

  private startNextRequest() {
    // get next request, if any.
    if (this.queue.length > 0) {
      this.execute(this.queue[0]);
    }
  }
}

One can use/call above service following way to make HTTP calls (from any other component or service) (Obviously you need to inject BackendService in the component e.g. Mention in provider of component and define in constructor):

    this.backendService.invoke('https://jsonplaceholder.typicode.com/posts', 'Get', null, null)
    .subscribe(
      result => {
        this.data = result;
      }
    );

In case of someone wants to look at working plunker then here is the working plunker.

How to prioritize certain HTTP requests from a Queue: Angular (2+) , Add the Interceptor to the Providers. QueueInterceptor is the Interceptor class we will be using to include the Queue based mechanism for the� Add queueing to Angular's HttpClient. Ask Question Asked 2 years, 6 months ago. Active 7 months ago. Viewed 6k times 3. 6. I have exact

You can do this relatively easily. A naive example follows bellow.

It lacks typing etc, it's not elaborate, it has a few weak points, and it would be better to extract the queueing part and http-requesting part into different services or classes, but this should get you started.

interface PendingRequest {
  url: string;
  method: string;
  options: any;
  subscription: Observable<any>;
}

@Injectable()
export class BackendService {
  // This is your private requests queue emitter.
  private requests$: Subject = new Subject();
  private queue: PendingRequest[] = [];

  constructor(private http: HttpClient) {
    // subscribe to that queue up there
    this.requests$.subscribe(request => this.execute(request));
  }

  // This is your public API - you can extend it to get/post/put or specific
  // endpoints like 'getUserProfile()' etc.
  invoke(url, method, options) {
      return this.addRequestToQueue(url, method, params, options);
  }

  private execute(requestData) {
    const req = this.httpClient.request(requestData.method, requestData.url, requestData.options)
      // as a last step, invoke next request if any
      .finally(() => this.startNextRequest());

    const sub = requestData.subscription;
    sub.switchMap(req);

  }

  private addRequestToQueue(url, method, options) {
    const sub = new Subject<any>();
    const request = new PendingRequest(url, method, options, sub)
    // if there are no pending req's, execute immediately.
    if (this.queue.length === 0) {
      this.requests$.next(request);
    } else {
      // otherwise put it to queue.
      this.queue.push(request);
    }
    return sub;
  }

  private startNextRequest() {
    // get next request, if any.
    if (this.queue.length) {
      this.execute(this.queue.shift());
    }
  }
}

serhiisol/ngx-request-queue: Angular 4.3.0+ Request , npm install ngx-request-queue --save npm install @decorators/common --save. Full example. Full example you can find in this repo� Angular is a platform for building mobile and desktop web applications. Join the community of millions of developers who build compelling user interfaces with Angular.

I have the exact same requirement as you. The other answers work perfectly fine, just that it requires developer to create requests with another a custom service instead of native HttpClient. You could try the following interceptor to apply queuing as well.

This solution requires you to add 2 services, a HttpInterceptor and a service (RequestQueueService) to manage the queue.

HttpInterceptor:

@Injectable()
export class QueueInterceptorService implements HttpInterceptor {
  constructor(private queueService: RequestQueueService) { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.queueService.intercept(request, next);
  }
}

RequestQueueService:

@Injectable({
  providedIn: 'root'
})
export class RequestQueueService {
  private queue: ReplaySubject<any>[] = [];

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const requestQueueItem$ = new ReplaySubject<any>();
    const result$ = requestQueueItem$.pipe(
      switchMap(() => next.handle(request).pipe(
        tap(req => {
          if (req.type == HttpEventType.Response) {
            this.processNextRequest();
          }
        }),
        catchError(err => {
          this.processNextRequest();
          throw err;
        })
      ))
    );
    this.queue.push(requestQueueItem$);

    if (this.queue.length <= 1) {
      this.dispatchRequest();
    }

    return result$;
  }

  private processNextRequest(): void {
    if (this.queue && this.queue.length > 0) {
      this.queue.shift();
    }
    this.dispatchRequest();
  }

  private dispatchRequest(): void {
    if (this.queue.length > 0) {
      const nextSub$ = this.queue[0];
      nextSub$.next();
      nextSub$.complete();
    }
  }
}

Lastly, in AppModule:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [
    RequestQueueService,
    { provide: HTTP_INTERCEPTORS, useClass: QueueInterceptorService, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

BTW, I am using Angular 8 with rxjs 6.4.

jseppi/angular-queue: Processing queue for AngularJS, Contribute to jseppi/angular-queue development by creating an account on var myQueue = $queue.queue(myCallback, options); myQueue.add('item 1');� Angular componentslink. The page you see is the application shell. The shell is controlled by an Angular component named AppComponent. Components are the fundamental building blocks of Angular applications. They display data on the screen, listen for user input, and take action based on that input.

The Answer from Ryan Teh works like a charm if you want to generalize all of your http requests in a cue, as it is a Catch All solution.

Here I expand it with the adequate imports for Angular 8.2.4 and rxjs 6.4.0 as there will be many users looking for cut n' paste

My apologies for the creating a new answer instead of a comment, i still don't have enough cred for that.

queue-interceptor.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { RequestQueueService } from './request-queue.service';

@Injectable()
export class QueueInterceptorService implements HttpInterceptor {
  constructor(private queueService: RequestQueueService) { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.queueService.intercept(request, next);
  }
}

request-queue.service.ts

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpEventType } from '@angular/common/http';
import { Observable, ReplaySubject } from 'rxjs';
import { tap, catchError, switchMap } from 'rxjs/operators'; 

@Injectable({
  providedIn: 'root'
})
export class RequestQueueService {
  private queue: ReplaySubject<any>[] = [];

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const requestQueueItem$ = new ReplaySubject<any>();
    const result$ = requestQueueItem$.pipe(
      switchMap(() => next.handle(request).pipe(
        tap(req => {
          if (req.type == HttpEventType.Response) {
            this.processNextRequest();
          }
        }),
        catchError(err => {
          this.processNextRequest();
          throw err;
        })
      ))
    );
    this.queue.push(requestQueueItem$);

    if (this.queue.length <= 1) {
      this.dispatchRequest();
    }

    return result$;
  }

  private processNextRequest(): void {
    if (this.queue && this.queue.length > 0) {
      this.queue.shift();
    }
    this.dispatchRequest();
  }

  private dispatchRequest(): void {
    if (this.queue.length > 0) {
      const nextSub$ = this.queue[0];
      nextSub$.next();
      nextSub$.complete();
    }
  }
}

and app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RequestQueueService } from './YOUR_SERVICES_DIRECTORY/request-queue.service';
import { QueueInterceptorService } from './YOUR_SERVICES_DIRECTORY/queue-interceptor.service';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [
    RequestQueueService,
    { provide: HTTP_INTERCEPTORS, useClass: QueueInterceptorService, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Angular Smart Interceptor — Queue of Requests - DEV, Let's create an Interceptor and add the Access Token to every request. I created a new folder /helper with these two files. Helper folder. “Main� heroes.component.html (HeroDetail binding) content_copy <app-hero-detail [hero] = "selectedHero" ></app-hero-detail> [hero]="selectedHero" is an Angular property binding. It's a one way data binding from the selectedHero property of the HeroesComponent to the hero property of the target element, which maps to the hero property of the HeroDetailComponent.

queue, const queue: any;. Description. Put every next task on a queue, instead of executing it immediately. queue scheduler, when used with delay, behaves the same� Processing queue for AngularJS. Contribute to Xtraball/angular-queue development by creating an account on GitHub.

Multiple HTTP Requests in Angular, Quick guide on how to do multiple HTTP requests in Angular - either sequentially or in parallel. Angular and Angular 2 is amazing now you are hearing that you should use observables rather than promises. That is a general tech challenge and we just have to get used to change and growth to build better and cooler stuff. Trust me you won't regret this one.

RXJS queue up multiple http requests and send when x conditions , RXJS queue up multiple http requests and send when x conditions happens � http typescript angular-2+ rxjs Your Answer. Body. Add picture� Angular CLI comes with a command ng build, which bundles your angular app into a dist folder, or a folder that you may specify in the angular-cli.json file. This is what our express app will point to. Install express and body-parser as dependecies. $ npm install--save express body-parser. Or if using yarn $ yarn add express body-parser

Comments
  • So what have you tried and what exactly is the problem with it? SO isn't a code-writing service.
  • So... what happens?
  • Don't you think here "invoke" method also should return Observable<any>, otherwise the how caller will get the response data? If I try to return Observable<any> to invoke method then ultimately it needs to returned from addRequestToQueue method and I don't know how addRequestToQueue will return Observable<any>
  • Yes, forgot about that part. You can add an observable in the queue, then switchMap or something once it gets off the queue and into execution.
  • Also, thanks for the downvote, whoever. I've thought the practice is to mention in the comments as to why you're downvoting a particular thing.
  • @HiteshShekhada there, subscription and error handling added.
  • Zlatko: thanks for directing me to correct approach.