1

I have an app which uses a login cookie which is sent with most api requests/calls to verify the user. (It is set by the server after a successful login.)

The problem is, that my app is doing a bunch of api calls simultaniously at startup which leads to calls with invalid session ids which are then recreated serverside for each of those calls, so they end up with different session ids => the user get's logged out.

My plan is to send a single api call before each others are allowed. But somehow i can't get it to work in the correct order.

I came up with a promise which will be resolved after the first call has finished in my wrappers constructor like so

private firstCallMade: Promise<any>;

constructor(
    private http: HttpClient,
    private settings: SettingsProvider)
  {    
    this.settings.getAsyncString("apiEndpoint").then(res =>
    {
      this.apiUrl = res;

      this.firstCallMade = new Promise((resolve, reject) =>
      {
        this.http.get(this.apiUrl + this.firstCallEndpoint, { withCredentials: true })
        .subscribe(
          (result) => {
            this.logger.system(this, 'First Call', `First call successful: ${JSON.stringify(result)}`);
            resolve();
          },
          (error) => {
            this.logger.system(this, 'First Call', `First call failed: ${JSON.stringify(error)}`);
            resolve();
          });
      });
    });
  }

And in the other wrapper methods i use it like so

  get<T>(endpoint: string): Observable<T>
  {
    return new Observable<T>(subscriber =>
    {
      this.firstCallMade.then(_ =>
      {
        this.http.get<T>(this.apiUrl + endpoint)
          .subscribe(
            next => subscriber.next(next),
            error => subscriber.error(error));
      });
    });
  }

But this does not work.

Is my code wrong?

EDIT FOR CLARIFICATION What is want is that all, but the first call can go simultaniously, after the first call has finished (thus setting the right cookie data for subsequent calls).

Velulian
  • 313
  • 5
  • 15
  • I think you are looking for the `forkjoin` function https://stackoverflow.com/questions/49327693/how-can-i-get-multiple-services-call-to-finish-before-emitting-an-event – rhavelka Jun 17 '19 at 15:38
  • 1
    have you looked into `APP_INITIALIZER`? You can run that single function you want before the others... – AT82 Jun 17 '19 at 18:46
  • @AJT_82 nice tip! But i don't want my app startup to wait/stall or even fail based on this web call. I want to be able to make calls that wait for the first call if it has not finished yet. – Velulian Jun 17 '19 at 23:15

1 Answers1

1

1 You don't need forkJoin, you need mergeMap or concatMap, forkJoin is bad normally, why? because if one request fails, then, everything else fails.

mergeMap and concatMap if one of ten requests for example fails, the other nine keeps trying to finish.

The difference between mergeMap and concatMap is the way they do the requests, in mergeMap they are sent to the server in "one push", I mean, lets think that you want to pull 10 dates, mergeMap then do the request for the 10 dates without waiting for the previous one to finish while concatMap waits for the previous to finish to add a new request to the queue.

Here you have an example of "how to use concatMap, mergeMap and forkJoin": https://angular-bojdob.stackblitz.io

Here it is from Tomas (english): https://blog.angularindepth.com/practical-rxjs-in-the-wild-requests-with-concatmap-vs-mergemap-vs-forkjoin-11e5b2efe293

Alex Onozor
  • 6,841
  • 1
  • 22
  • 26