Search code examples
rxjs6

RxJS Resolve a sequence of observables where each depends on the previous ones


I need to make a series of http calls, where each call depends on the previous responses (bodies or headers). How can I achieve this with Observables?

So far I've made the ugly nested subscriptions:

this.http.get(url1)
.subscribe(response1 => {
    const params1 = something(response1);
    this.http.post(url2, params1)
    .subscribe(response2 => {
        const params2 = something(response1,response2);
        this.http.post(url3, params2)
       .subscribe(response3 => {
           const params3 = something(response1,response2,response3);
           this.http.post(url4, params3)
           .subscribe(response4 => {
               const params4 = something(response1,response2,response3,response4);
               this.http.post(url5, params4)
               .subscribe(response5 => console.log(response5));
           });
       });
    });
});

Solution

  • You could try using the flatmap rxJS operator for better readability. I think it would look like the following. rxJS6, you will need to use the pipe operator for this to work.

    Simpler Example

    Here is a more built up example solution to understand whats going on.

    public test(): Observable<any>
    {
        return of([1]);
        //when subscribed to returns [1]
    }
    
    public testTwo(value): void
    {
        console.log(value); // [1] <- comes from the observable
        this.fromEndpoint = value;
    }
    
    public testThree(example): Observable<any>
    {
        if (example[0] === 1)
        {
            return of([3]);
            // return an array of [3] when subscribed to.
        }
    }
    
    public ngOnInit()
    {
        this.test().pipe(flatMap(response1 => (this.testTwo(response1), 
        this.testThree(response1)))).subscribe(final => 
        {        
            console.log(final); 
            // this logs ['3'] as the calls are chained with flatMap
        }); 
    }
    

    Im hoping the more simple example I have put together will make it a little easier to understand. That leads me to think you could do the following for the code you have provided.

    Solution

    this.http.get(url1).pipe(
      flatMap(response1 => (this.exampleFunction(response1), this.http.get(response1))),
      flatMap(response2 => (this.responseValue = response2, this.http.get(response2))),
      flatMap(response3 => (this.exampleFunctionThree(response3), this.http.get(response3)))
    ).subscribe(final => {
        console.log(final);
        console.log(this.responseValue);
    });  
    

    Note that the console.log(final); will only log the result of the last observable / api call and not collect values along the way. if you needed to collect all the values, you can pass in a separate function to send the response to, or declare it as you go along in a higher scope. I have shown that in the above example.

    Documentation

    flatmap and switchmap

    of and subscriptions as they are used in example

    flatMap is an alias for mergeMap!