Edwin
Edwin

Reputation: 961

RXJS: Combining the results of multiple endpoint calls into a single array

I have an RXJS Pipeline similar to this:

const logs: number[] = [1, 2, 3, 4];
const url = 'http://some-url-here.com';

const pipeline = from(logs).pipe(
  switchMap(logId =>
    this.callEndpoint(url, logId).pipe(map(response => response.data)),
  ),
);

const res = await pipeline.toPromise();
console.log(res);



// The real function uses nestJS http service to call a url
callEndpoint(url: string, logId: number) {
  const result = Math.random() * 1000;
  console.log(`result in callEndpoint: ${result}`);
  return of({ data: result });
}

here is a sample output of the code:

result in callEndpoint: 586.773956063481
result in callEndpoint: 842.136341622411
result in callEndpoint: 964.0849490798163
result in callEndpoint: 598.7596176858414
598.7596176858414

The last number is the result of res.

How do I get the combined results of all the successful endpoint calls into a single array in res?

Upvotes: 0

Views: 727

Answers (2)

frido
frido

Reputation: 14129

Use forkJoin if you want to send all requests at once or concat with toArray to send requests sequentially and collect the results in an array. You probably want to add error handling with catchError and return an observable that doesn't error in this case.

const getData = (logId) => this.callEndpoint(url, logId).pipe(
  map(response => response.data),
  catchError(error => of(null))
)
const requests = logs.map(logId => getData(logId));

// parallel requests
forkJoin(requests).subscribe(res => console.log(res));

// sequential requests
concat(...requests).pipe(toArray()).subscribe(res => console.log(res));

res will be an array that can contain null values if a request failed. When the second request fails this might look like:

[586.773956063481, null, 964.0849490798163, 598.7596176858414]

Upvotes: 2

martin
martin

Reputation: 96949

You can use toArray() to collect all emission and emit them as one array after the source observable completes.

const pipeline = from(logs).pipe(
  switchMap(logId =>
    this.callEndpoint(url, logId).pipe(map(response => response.data)),
  ),
  toArray(),
);

However, I think you don't want to be using switchMap in this case because the source observable here is from() that will emit all items from logs immediatelly and switchMap will keep subscribed only to the last one. So you might want to use concatMap instead.

Upvotes: 1

Related Questions