0

I'm hoping someone can offer a little advice on how to do the following:

I have a requirement to chain multiple http requests with each one dependant on the result of the previous.

i.e

Step 1: Login User

Step 2: Authenticated Http request

Step 3: Authenticated Http request with response value from Step 2

Step 4: Authenticated Http request with response value from Step 3

So far I have the following code (which works):

this.authSandbox.login(this.loginForm).subscribe(() => {

    this.customerEnquirySandbox.createCustomer(newCustomer)
    .filter(response => !!response) // continue when response not null
    .subscribe((response) => {

        let response1Details = {
            "id": response.data.id,
        };

        this.customerEnquirySandbox.createMeasure(response1Details )
        .filter(response => !!response)
        .subscribe((response) => {

            let response2Details =  {
                "id": response.data.id,
            };

            this.customerEnquirySandbox.saveAnswers(response2Details )
            .filter(response => !!response)
            .subscribe((response) => {

                if (response.data.success) { 
                    alert('Form completed and answers saved successfully');
                } else {
                    alert('Error submitting answers');
                }

                this.authSandbox.customerEnquirylogout();
            });

        });

    });

});

The above works but doesn't seem like the most appropriate way. I've seem suggestions using switchMap but am not sure if this is the right approach. If anyone can offer any guidance on how to do the above more correctly then it will be much appreciated.

Thanks in advance

ledragon
  • 299
  • 6
  • 17

1 Answers1

1

Like JB suggested, switchMap is the way to go if each subsequent call relies on the previous, while if they can be done in parallel, then zip is a great option. Here is your code refactored to use switchMap

this.authSandbox.login()
    .pipe(
        filter(response => !!response),
        switchMap(response => {
            return this.customerEnquirySandbox.createCustomer(newCustomer);
        }),
        filter(response => !!response),
        switchMap(response => {
            return this.customerEnquirySandbox.createMeasure(response.data);
        }),
        filter(response => !!response),
        switchMap(response => {
            return this.customerEnquirySandbox.saveAnswers(response.data);
        }),
        filter(response => !!response),
        switchMap((response): Observable<never> => {
            if (response.data.success) {
                alert('Form completed and answers saved successfully');
            } else {
                alert('Error submitting answers');
            }
            this.authSandbox.customerEnquirylogout();
            return EMPTY; /* EMPTY is a Observable which immediately completes */
        }),
    );

Learn about switchMap here

Another benefit of using this approach is that you can move the subscription down to the level which needs the value such as a component. For services, typically you just manipulate the Observable's output by treating it like a stream and applying operations on it.

Jack W
  • 19
  • 5
  • Unfortunately the compiler doesn't like the syntax...thanks anyway – ledragon Jul 26 '19 at 11:07
  • @ledragon if you don't post the code you tried and the error you got, we can't help you. The code you posted in your question shows you're using an obsolete version of RxJS. Angular is now at version 8, and since version 6, it uses RxJS 6. You're using an older version. Time to upgrade. – JB Nizet Jul 27 '19 at 06:55