Angular2: dynamic synchronous HTTP requests

Purpose: Make a series of synchronous HTTP requests and subscribe to them as one monitored stream.

Example (does not work):

let query_arr = ['test1','test2','test3']

function make_request(query_arr){

    if (query_arr.length){

        let payload = JSON.stringify(query_arr[0]);
        let headers = new Headers();

        query_arr.splice(0,1);

        this.http.post('https://endpoint/post',payload,{headers:headers})
            .map((res:Response) => {make_request(query_arr)})

    }

}.subscribe(
    data => console.log('finished http request, moving on to next http request'),
    err => console.error(err),
    () => console.log('all http requests have been finished')
);

make_request(query_arr)

Target Functionality:

  • You need to know when the response was returned.
  • Gotta know when all the answers have returned.
+2
source share
3 answers

You need to use the operator flatMapto execute your queries sequentially (one by one). To do this, you need to recursively build your data processing chain. The point here is to call the operator on the previous observable (returned by the previous request).

, , . , , .

:

makeRequest(queryArr, previousObservable){
  if (queryArr.length) {
    let payload = JSON.stringify(queryArr[0]);
    let headers = new Headers();
    (...)

    queryArr.splice(0,1);

    var observable = null;
    if (previousObservable) {
      observable = previousObservable.flatMap(() => {
        return this.http.post('https://testsoapi.apispark.net/v1/entities', payload,{
            headers:headers
          })
          .map((res:Response) => res.json())
          .do(() => {
            console.log('request finished');
          });
      });
    } else {
      observable = this.http.post('https://testsoapi.apispark.net/v1/entities', payload, {
        headers:headers
      })
        .map((res:Response) => res.json())
        .do(() => {
          console.log('request finished');
        });
    }

    return this.makeRequest(queryArr, observable);
  } else {
    return previousObservable;
  }
}

:

test() {
  let queryArr = [
    { val: 'test1' },
    { val: 'test2' },
    { val: 'test3' }
  ];

  this.makeRequest(queryArr).subscribe(
    () => {
      console.log('all requests finished');
    });
}

plunkr: https://plnkr.co/edit/adtWwckvhwXJgPDgCurQ?p=preview.

+5

, . , concatMap + defer.

let query_arr = ['test1','test2','test3'];
let self = this;

Rx.Observable.from(query_arr).map(JSON.stringify)
  .concatMap(payload => {
    let headers = new Headers();
    return Rx.Observable.defer(() => {
      self.http.post('https://endpoint/post',payload,{headers:headers});
    });
  }, resp => resp.json())
  .subscribe(
    data => console.log('finished http request, moving on to next http request'),
    err => console.error(err),
    () => console.log('all http requests have been finished')
  );

, Observable, , . , defer, .

+1

Or a non-recursive version in typescript where you give a forkjoin array

in return observableObj (res.json ()), you know every answer when it comes back from httpcall

in the subscription you know when all responses and an array of values ​​are returned

const observableObj = (obj) => Observable.of(obj)

class Requests {

 private query_arr = ['test1','test2','test3']
 private url = 'https://testsoapi.apispark.net/v1/entities'

 public make() {
   this.processHttp().subscribe(
        (d) => {
          console.log(d)              
        },
        (e) => {
          console.log(e)
        },
        () => {
          console.log("http calls are done")
        })

 }

 private httpCall(options : RequestOptions) : Observable<Response> {
   let username : string = 'xxx'
   let password : string = 'yyy'
   let headers = new Headers()
   headers.append("Authorization", "Basic " + btoa(username + ":" + password))
   headers.append("Content-Type", "application/x-www-form-urlencoded")
   options.headers = headers
   return this.http.get(this.url,options)
 }

 private createRequestOptions(option1 : string) {
   let data = {'option1':option1}
   let params = new URLSearchParams()
   for(var key in data) {
     params.set(key, data[key])
   }
   let options = new RequestOptions({
     search: params
   })
   return options
 }

 private processHttp() {
    return Observable.forkJoin(
        this.query_arr.map(option => {
            return this.httpCall(createRequestOption(option)).flatMap((res: Response) => {
                return observableObj(res.json())
            })
        }))            
 }
}
0
source

All Articles