How to call multiple URLs and only handle the first value that returns using RxJS?

Mike

I have multiple URLs that contain information. I have an ID I am trying to look up but do not know which URL contains the information I need. I am trying to call each URL and whichever returns a valid response first, use that and cancel the other calls.

I have attempted to use race() to do this, but have run into an issue where it will take the result from the Observable to complete, even if that Observable has not emitted any values (or they have been filtered out). I have tried to resolve this by doing .concat(never()) on each Observable, but then it seems like race() does not cancel the Observables after the fact, meaning I cannot reuse them for subsequent calls.

const urls = ['url1', 'url2', 'url3']

private getItem(id: string): Observable<string> {
    return race(
        ...this.makeUrlCalls(id),
        timer(10000).pipe(flatMap(() => of(''))),
    )
}

private makeUrlCalls(id: string): Array<Observable<string>> {
    return urls.map(url => {
        return this.http.get<any>(url + id).pipe(
            map(({items: [item]}) => item),
            filter(Boolean),
            concat(never()),
            retry(2),
        )
    })
}

What I want to happen is that whenever a URL returns a result, the first one that has a valid value (non-empty array called item) is returned from the race() call.

Any help is greatly appreciated!

joh04667

You can use merge to combine all the Http calls into a single Observable, and then use first on the combined Observable with a predicate function. The combined Observable will only emit the first inner Observable emission that passes the predicate.

const urls = ['url1', 'url2', 'url3']`;

private getItem(id: string): Observable<string> {
    return merge(...this.makeUrlCalls(id))
        .pipe(first(s => !!s.length))

}

private makeUrlCalls(id: string): Array<Observable<string>> {
    return urls.map(url => {
        return this.http.get<any>(url + id).pipe(
            map(({items: [item]}) => item),
            concat(never()),
            retry(2),
        )
    })
}

I took the filter off the mapped array, because that could be handled with the higher-level merge operator. In fact, the filter method could block emissions in conjunction with first() instead of passing a predicate method to first.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Function returns only first value

Lists returns only the first value

How to call multiple dependent api calls with time intervals using RxJS

RxJS .toPromise returns only one value

RxJS - Observable is not emitting value with .next() on first call

How to handle multiple returns in javascript

map multiple callback returns into observable using RxJs

Trying to create a function that takes two long values and returns true if and only if the first value is a multiple of the second value

How to create an RxJS Observable such that it returns a value when call back function completes

How to handle multiple components using the same v-model value

Python - Intersection of sets returns only the first value

While loop returns only first row value

Why select returns only the first value?

Function returns only the first value of the input variable

Laravel foreach only returns first value

Only returns the first value of x=a or 'start' variable

Using DocBlocks - how to indicate that a function returns a value only in some conditions?

dplyr: How to handle multiple value

Initializing a value only on the first call to a recursive function

How can I Get Only One Item using Rxjs First() Operator

How to skip first value of an observable with RxJS?

How to make sure that click event will fire only after http call come back using RxJS

how to call multiple URLs within array at same time using node js

How can I handle only the first part of my value list of a dictionary in Python?

How to handle dependent http service call subscription by RxJs operators?

How to handle ARRAY_LITERAL with multiple QUERY()'s when one of them returns no value in Google Sheets?

How to call only the second value of a class in python, while keeping the first value as default?

RxJs Zip only takes the first value from the sent stream

How to scrape using multiple urls after extracting a specific html value using Beautiful Soup