How can RxJS be used to handle only the first value returned when calling multiple URLs?

I am faced with the challenge of having multiple URLs containing crucial information. My goal is to find a specific ID within these URLs, but I do not know which URL holds the necessary details. The approach I'm taking involves calling each URL and using the first one that provides a valid response, while canceling the other calls.

Initially, I tried using the race() function for this task. However, I encountered an issue where it would wait for the completion of the Observable, even if no values were emitted or they had been filtered out. To address this, I attempted to add .concat(never()) to each Observable. Unfortunately, this caused race() to fail in canceling the Observables afterward, making them unusable 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),
        )
    })
}

The desired outcome is to have the first URL that returns a valid value (non-empty array named item) be used from the race() call.

Any assistance on solving this predicament would be highly valued!

Answer №1

To consolidate all Http calls into a single Observable and retrieve the first emission that meets a certain criterion, you can utilize the `merge` method followed by `first` on the combined Observable with a specific predicate function. This approach ensures that only the initial inner Observable emission fulfilling the criteria will be emitted.

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),
        )
    })
}

The decision to eliminate the `filter` from the mapped array was intentional as it can be efficiently managed using the higher-level `merge` operator. By omitting the `filter`, emissions can be controlled in tandem with `first()` rather than utilizing a predicate function within the `first` operator.

Answer №2

Utilize rxjs takeUntil to finish any outstanding http requests, as demonstrated below:

let stop$ = new Subject();
request
  .pipe(
    ...
    takeUntil(stop$)
  );
race(...)
  .subscribe(() => {
    // alternatively use finalize
    stop$.next();
  });

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Discovering the proper way to namespace or target a variable input within a component

Consider the following: mat-button directive is affected by a disabled attribute / input. matTooltip directive is also impacted by a disabled attribute / input. Can you design a material button that appears disabled, but still has an active tooltip asso ...

Unable to construct a node typescript project using solely production dependencies

I am currently working on a Node TypeScript project that utilizes various third-party libraries such as express. To ensure type safety, I typically install the @types/express module as a dev dependency following common instructions. The installation works ...

What is causing Angular to consistently display the first object in the array on the child view, while the child .ts file correctly prints information from a different object?

Once a card of any object is clicked, the information of that specific object will be printed to the console. However, the child view will only display the details of the first object in the array it retrieves from. All pages are included below. A visual e ...

A guide on accessing information from nested arrays in JavaScript

I am having trouble retrieving data from a JavaScript array as it keeps showing undefined. Here is the code snippet: sabhaDetailsArrayTemp.forEach(element => { let arra = []; console.log(element) //return tmp.m_category_name ; arra = this.onSa ...

Show data based on the chosen destination

Recently, I've been working on creating a simple printer manager to monitor the status of all my printers. Although I have successfully displayed all the data, I'm facing an issue while trying to organize it by location. The error message I keep ...

What is the best way to retrieve an object when a value is not found? Consider implementing a looping mechanism with a specific condition in React and TypeScript to successfully

Greetings, I am faced with an array of objects structured as follows: const arr_obj = [ { id: '1', jobs: [ { completed: false, id: '11', run: { ...

What is the maximum number of groupings that can be created from a set of numbers within a

I'm trying to figure out how to handle a specific task, but I'm running into some obstacles. When adding numbers to clusters, a number is considered to belong to a cluster if its distance to at least one existing number in the cluster is within a ...

Exploring the possibilities of utilizing JavaScript within TypeScript

My dynamic javascript object holds all the resources (translation strings) for my app. Here's how it is structured: var ResourceManager = (function () { function ResourceManager() { var currentLanguage = $('#activeLanguage').htm ...

How to display document files (.doc or .docx) using a byte array in Angular 4

I am facing a challenge in viewing all the attachments submitted by users. While I can easily view PDF and image files, I seem to have trouble with files having .doc or .docx extensions. Here is my current approach: let file = null; if (extension === &a ...

Exploring Parquet Files with Node.js

Looking for a solution to read parquet files using NodeJS. Anyone have any suggestions? I attempted to use node-parquet but found it difficult to install and it struggled with reading numerical data types. I also explored parquetjs, however, it can only ...

How can I sort by the complete timestamp when using the Antd table for dates?

I have an item in my possession. const data: Item[] = [ { key: 1, name: 'John Brown', date: moment('10-10-2019').format('L'), address: 'New York No. 1 Lake Park', }, { ...

Navigating through various product categories in Angular's routing system

Greetings! I am currently building a Shop Page in Angular 4 and encountering an obstacle with Angular routing. The issue arises when a user clicks on a product category, the intention is for the website to direct them to the shop page. On the homepage, th ...

The ngIf statement in the template isn't functioning properly after a refresh; instead, it is causing a redirection to the homepage

I've been developing with Angular 7, trying to display a <div> ... </div> based on multiple values that I declared as : Boolean = false; in the .ts file. These values are updated in ngOnInit, but for some reason, the page keeps redirecting ...

When using the map function, I am receiving an empty item instead of the intended item based on a condition

Need assistance with my Reducer in ngRx. I am trying to create a single item from an item matching an if condition, but only getting an empty item. Can someone please help me out? This is the code for the Reducer: on(rawSignalsActions.changeRangeSchema, ...

When utilizing useRef and useCallback in React, the output is visible in the console log but does not appear on the page

When working with API data, it's important to remember that the extraction process is asynchronous and the state may not be available at certain times. To handle this situation, we can utilize useCallback. However, even after successfully logging the ...

Step-by-step guide on incorporating a climate clock widget into your Angular project

Is there a way to integrate the Climate Clock widget from into my Angular project? Upon adding the following code snippet: <script src="https://climateclock.world/widget-v2.js" async></script> <script src="https://climateclo ...

Local variables are now being refreshed with every modification in the data stored in Cloud Firestore

Having trouble maintaining the accuracy of my local variables in sync with changes to the data in cloud firestore. Specifically, in my local variable called count_vehicle, the value represents a count based on specific conditions from the data in cloud fir ...

Angular element fails to display properly

I'm currently working on developing a website using Angular and creating a header component. To generate the necessary files, I used the command ng g c commons/header which creates the HTML, SCSS, TS, and .spec.ts files. I then made modifications to t ...

The issue arises when attempting to invoke a method from a global mixin in a Vue3 TypeScript component

I've been working on this challenge for the past week, and I would appreciate any help or insights from those who may have experience in this area. Currently, I am in the process of converting vue2-based code to vue3 for a new project. Instead of usi ...

Changing the format of a numerical value to include commas for every 1000 increment

I'm trying to find a way to format numbers in a specific manner, such as changing 1234567 into 1,234,567. However, I've run into some issues when attempting to use the currency pipe of TypeScript. It adds USD or $ in front of the number, which i ...