Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observable Continue calling API and changing parameters based on condition

I've read the Rx.js repeat Documentation in an effort to find out how I can continue calling an api based upon the response that I receive from the API. I'm calling an API that can only send back 2k records at a time. The API will send back a value for me to send it so that I can continue receiving the records until they return a done value.

So the flow goes as follows:

  1. Make a GET request a query parameter reqMode='':
  2. retrieve response with the last array containing reqMode with a value or done.
  3. If I receive a value then I need to make the same request but send the reqMode parameter with the value.
  4. If i receive done then I'll stop and return all of the records since the first call.

I get the first set of values when subscribing normally, but this would be my attempt after reading the docs, but it doesn't make sense:

getRecords(){
    let url = this.url + 'reqMode=';
    return this.http.get(url)
            .doWhile() //What would I do here
}

When trying to do .doWhile with a Observable that is type Observable<response>. I'm looking for any alternative using Observables for what I need to do.

like image 750
Abdullah Rasheed Avatar asked Dec 14 '22 03:12

Abdullah Rasheed


2 Answers

I don't think repeat() is a good operator for this. If I understand you correctly you want to repeat the HTTP request based on the response of the previous request. Operator repeat() is good if you wanted to repeat the same request multiple times.

I'd use concatMap() and recursively call itself until the reqMode is eqaul to "done":

See live demo: http://plnkr.co/edit/w0DdepslTaKrLSB3aIkA

import {Observable, Subject} from 'rxjs';

const result = new Subject();
const closeBuffer = new Subject();
const buffer = result.buffer(closeBuffer.asObservable());

function sendHttpRequest(reqMode) {
  return Observable.of('{"reqMode":' + reqMode + '}')
    .map(response => JSON.parse(response))
    .concatMap(data => {
      console.log('HTTP Response:', data);
      // Add data to the buffer of results
      result.next(data);

      if (data.reqMode == 'done') {
        // Return an empty value wrapped as an Observable so concatMap can work
        // with it and emit onNext when it completes (which is immediately
        // thanks to the `.of()` operator).
        return Observable.of(null);
      } else {
        // Simulate that the next call returns 'done'
        return sendHttpRequest('"done"');

        // Uncomment this for real usage
        //return sendHttpRequest(data.reqMode);
      }
    });
}

// Subscribe to the buffer where I'll receive the value.
buffer.subscribe(val => console.log('Next: ', val));

// Simulate HTTP request with reqMode = 42
sendHttpRequest(42).subscribe(() => {
  console.log('done');
  // Emit values from the buffer.
  closeBuffer.next(null);
  closeBuffer.complete();
});

I use of() operator to simulate a request and to return a value wrapped as an Observable. I also use Subject to hold all responses that are buffered using buffer() operator. The I subscribe to the buffer to get the final array of responses (If you wrap this code into a function you'll most likely return the buffer where you can subscribe later).

The response is following:

HTTP Response: Object {reqMode: 42}
HTTP Response: Object {reqMode: "done"}
Next:  [Object, Object]

See similar question: Angular 2 + rxjs - how return stream of objects fetched with several subsequent http requests

like image 170
martin Avatar answered Dec 18 '22 10:12

martin


So I made an example on how you can do this by using a wrapping observer and using .repeat().

All the logic is in app.component.ts

Checkout this plunker

I left comments in the code, but essentially it will make an http request, it will increment a count, and then will make another request with a different query number. It will repeat until it reaches 5.

You will have to modify it so the "repeat condition" represents your logic.

Hope that helps!

like image 31
mrcolombo Avatar answered Dec 18 '22 11:12

mrcolombo