4

I have a hard time figuring out how to create a recursive loop to api calls with Observables.

Scenario: I call external API, which returns something like this:

{
 data: {something, something, something},
 next: "url for next set of data"
}

I need to keep on calling the same function to gather all the data into a single object as long as the response has value in the next.

I managed to do this on another project with Promises where I map the data returned into single array by using the concat() function but I somehow cannot get my head around understanding how I should do this with Observables.

Working example with using promises:

getData: function(url, params, headers){
    return new Promise((resolve, reject) => {
        axios.get(url, {
            params: params,
            headers: headers,
        }).then((response) => {
            let responseData = response.data.data[0];
            if (response.data.next) {
                this.getData(response.data.next, {}).then((resp) => {
                    for (let dataSet of responseData.dataSets) {
                        let row = resp.dataSets.find(i => i.variable === dataSet.variable)
                        if (row) {
                            dataSet.data = dataSet.data.concat(row.data)
                        }
                    }
                    resolve(responseData);
                }).catch((error) => {
                    reject(error)
                })

            } else {
                resolve(responseData);
            }
        }).catch(error => {
            reject(error)
        })
    })
}
2
  • You may post your codes here that you did with promise. Commented Jun 6, 2018 at 7:02
  • Edited the question to include example Commented Jun 6, 2018 at 7:05

3 Answers 3

4

You can use the .expand() operator. The terminating condition for this recursion is when the next property is falsy. Use a ternary operator and the code is just one liner:

expand(({data, next}) => next ? getData(next): Observable.empty() )
    .subscribe(result => console.log(result));

Here is the working JSBin. I mocked quite a few stuffs but it should be quite trivial.

Sign up to request clarification or add additional context in comments.

1 Comment

Very helpful, i got the calls working and it's easy to read. Only part I dont quite get is how to map out the data, concatMap is not by itself solving the issue as I only want to concate data inside the dataset... Sorry, i'm having awfuly slow day today...
1

End solution that worked for me:

let obs = this.getData(endpoint, options).pipe(
  expand(({ next }) => {
    // This could be oneliner but I had to alter options for the calls after the first one for my own case
    return next ? this.getData(next, options) : Observable.empty()
  }),
  concatMap(({data}) => data)
)

obs.subscribe(
  data => mapthedata(data),
  error => error,
  complete => {
    // do something with the mapped data
  }
)
function mapthedata(data) {
  // here you should combine the data results into one, f.ex pushing to local variable
}

Comments

1

Just got into this similar problem today, here's my attempt. I think the hard part is to think correctly about what you're trying to achieve and then find the correct operator to support that.

In this case, from the first observable, we want to expand that and continue to emit values recursively until complete. What we want to collect at the end is all the emitted values from this observable and that's when I googled the correct keywords and found toArray to support this case.

Reference: How to collect array of emitted values from Observable.from?

this.getData(endpoint, options).pipe(
  expand(({ next }) => {
    return next ? this.getData(next, options) : Observable.empty()
  }),
  toArray(), // wait for the observable to complete and collect all emitted values
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.