6

I am kind of new to Angular 4 and Observables and everything related to it. I am trying to execute two http requests one after another (only when the first one succeeds).

I'm using this code:

public getCompany(id: string): any {
    let company = null;

    this.authService.isValidUser().subscribe(response => {
      const token = this.tokenStorageService.getTokenFromStorage();
      const requestUrl = environment.gatewayUrl + environment.companyService + environment.getCompanyEndPoint + id;
      const headers = new Headers();
      headers.set('Authorization', 'Bearer ' + token);
      const options = new RequestOptions({headers: headers});

      return this.http.get(requestUrl, options).catch(this.errorService.handleError);

    }, (error: AppError) => {
       // ........ //
    });
  }

This is the isValidUser() method code:

  public isValidUser(): any {
    const token = this.tokeStorageService.getTokenFromStorage();
    if (!token) {
      console.log('cannot find token');
      return false;
    }

    const requestUrl = environment.gatewayUrl + environment.authorizationService + environment.userServiceEndPoint;
    const headers = new Headers();
    headers.set('Authorization', 'Bearer ' + token);
    const options = new RequestOptions({headers: headers});

    return this.http.get(requestUrl, options).catch(this.errorService.handleError);
  }

The idea here is to only return return this.http.get(requestUrl, options).catch(this.errorService.handleError); after the authService.isValidUser() code worked.

I don't think this is a proper way of performing such requests, since my second request is already completed before the first one does.

Maybe I am missing some way on how to do it properly?

Thank you.

Deniss M.
  • 3,617
  • 17
  • 52
  • 100

1 Answers1

4

Where is code where you try to chain these two functions?

You can achieve what you want using switchMap operator. Here is docs for it.

I think you need something like this:

isValidUser()
  .filter(isValidUser => isValidUser) // <-- perhaps you need this filter since you want to make getCompany call only if user is valid
  .switchMap(() => getCompany())
  .subscribe(...do something...);

Don't forget to add import 'rxjs/add/operator/switchMap';. You can also use mergeMap or flatMap (mergeMap is synonim for flatMap), but it is not preferred.

As @BeetleJuice mentioned in comments: Why switchMap is better? For example, you use mergeMap or flatMap and something caused another call of that code. Even if two first requests was not finished new ones will be sended. It is even possible that second bundle of requests will be finished faster than first one. After that first bundle finishes and you have wrong data in your state. To solve this RxJS provides perfect operator switchMap. If you used this operator in situation above then first observable (first request bundle) will be cancelled. Only last observable (from last call) will stay alive. You need switchMap only if you have possibility to run that code several times in a short period of time. If you know that this code will run only once mergeMap/flatMap will do same for you.

Also, check out this post.

Update 3/28/2020: With new versions of rxjs, you can no longer call the switchMap operator on the returned Observable. Instead, you need to call pipe on the observable and pass in what should happen afterwards. For example:

isValidUser()
  .pipe(
    switchMap(() => getCompany())
  )
  .subscribe(...do something...)

Multiple operators can be passed into the pipe function as well. More info can be found on the rxjs site on the operators page

MadCityDev
  • 316
  • 2
  • 6
Sharikov Vladislav
  • 7,049
  • 9
  • 50
  • 87
  • Cool . Then thats the answer. – Sharikov Vladislav Aug 28 '17 at 13:32
  • 3
    Sharikov, @DenissM. `switchMap` is a better option than `mergeMap` because in this use case, you would want to preserve the order of execution -- the second http request should only ever be made after the first one resolves. `mergeMap` allows for the possibility that several requests of the first type are made while a slow second request is over the wire. – BeetleJuice Aug 28 '17 at 13:47
  • @BeetleJuice I updated. I tried to explain same using my explanation. Do you think everything is correct? Or should I fix? – Sharikov Vladislav Aug 28 '17 at 13:59
  • Thanks. I think it's correct, but it will be up to the OP to test whether it works in his or her project – BeetleJuice Aug 28 '17 at 14:02
  • @SharikovVladislav I'll test tomorrow and let you guys know. Thanks a lot! I was thinking about switchMap also, because that one made more sense in my case when I read about it before. – Deniss M. Aug 28 '17 at 17:31
  • @SharikovVladislav please fix the import for `switchMap` to `rxjs/add/operator/switchMap;` – Deniss M. Aug 29 '17 at 07:31
  • @DenissM. Fixed. Sry. – Sharikov Vladislav Aug 29 '17 at 07:32