Consecutive requests to APIs using RxJs

Is it possible to efficiently make sequential API calls using RxJs? The challenge lies in the fact that the first Observable emits an array, and for each item in this array, a custom URL should be set for the next call. Additionally, certain conditions need to be checked in the second call before returning an Observable.

I'm struggling with setting the URL for each element of the array as it changes. Can anyone provide guidance on how to achieve this?

  private fetchData(): Observable<boolean> {
    return this.service
      .getItems()
      .pipe(
        map((response) => response.items),
        mergeMap((result) => {
          result.map((order) =>
            this.orderService.setCustomUrl(order.number)
          );
          return this.orderService.getItems().pipe(
            mergeMap((response) => {
              if (response.items.some((item) => item.number === this.model.number)) {
                return of(true);
              } else {
                return of(false);
              }
            }),
          );
        })
      );
  }

Answer №1

The issue here arises because you are calling the setCustomUrl() function without utilizing .getItems() until after the completion of the map() operation. By the time .getItems() is invoked, the service has already received the final item from .map().

To achieve the desired outcome, you can implement the following code snippet:

function fetchData(): Observable<boolean> {
  return this.service
    .getItems()
    .pipe(
      map((response) => response.items),
      switchMap(items => from(items).pipe(
        concatMap(item=>{
          this.orderService.setCustomUrl(item.number);
          return this.orderService.getItems().pipe(
            map(response => response.items.some((item) => item.number === this.model.number))
          );
        }),
        toArray()
      )),
      map(items => items.some(item => item))
    );
}

The from() operator breaks down an array and emits each value individually, allowing us to perform the .some() check for boolean values.

Subsequently, the toArray() method collates these values back into an array for further processing.

Finally, a last map() operation evaluates if all items meet the specified criteria.

Answer №2

Here is a breakdown of what is happening in your code:

        {
          // Loop through each element in the "result" array and call "this.orderService.setCustomUrl(order.number)"
          result.map((order) =>
            this.orderService.setCustomUrl(order.number)
          );
          // Assuming "setCustomUrl" is setting a single variable, only the last "order.number" will be set at this point

          // Afterwards, this part executes once and returns a boolean value for the last order
          return this.orderService.getItems().pipe(
            mergeMap((response) => {
              // Check if any item number in the response matches with "this.model.number"
              if (response.items.some((item) => item.number === this.model.number)) {
                return of(true);
              } else {
                return of(false);
              }
            }),
          );
        }

The intended goal seems to be verifying if any order returned by this.orderService.getItems() using order.number has an item number matching this.model.number. Here is a revised approach you could take:

Firstly, modify your service call to include the order number like so:

this.orderService.getItems(order.number)

Then, consider the following implementation:

private func(): Observable<boolean> {
    return this.service
      .getItems()
      .pipe(
        switchMap((orders) =>
          from(orders.items).pipe(
// For each item in the initial response, return an observable that maps its result to a boolean as per your original function
            mergeMap((order) =>
              this.orderService
                .getItems(order.number)
                .pipe(map((itemsResponse) => itemsResponse.items.some((item) => item.number === this.model.number)))
            )
          )
        ),
// Collect all the boolean observables and yield only when all resolve
        toArray(),
// Aggregate all boolean values into one
        map((all) => all.some((x) => x)),
// Complete the subscription after the first yield
        take(1)
      )

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

Utilizing Angular to reference a computed variable in a different function while iterating through a loop

I recently started learning Angular 5 and coming from a background in PHP, I am finding variables a bit confusing. Currently, I am working on a loop where I want to use a calculated variable in another function within that same loop. Here is the code snip ...

Guide on how to add a generic return type to a function in typescript

Is there a way to annotate a function that returns a factory in TypeScript to ensure it contains correct type definitions? Consider the following code: class item<T> { constructor(a: T) { this.a = a; } a: T } function generate(c) { ret ...

What is the best way to bypass TS1192 when incorporating @types/cleave.js into my Angular application?

Using cleave.js (^1.5.2) in my Angular 6 application, along with the @types/cleave.js package (^1.4.0), I encountered a strange issue. When I run ng build to compile the application, it fails and shows the following errors: ERROR in src/app/app.component. ...

Encountered a MongoDB error: $pushAll modifier is unrecognized when trying to update a model using Mongoid, Angular, and Rails frameworks

My stack includes angular-8 on the front-end and Rails(5.2) on backend with Mongoid(6.1). I'm working with a multi-level nested form for my Event model, which utilizes accepts_nested_attributes_for for Ticket that in turn accepts_nested_attributes_fo ...

Leveraging WebStorm's TypeScript support in conjunction with node_modules

Attempting to set up a TypeScript project in WebStorm to import a Node.js module has been a struggle. I made sure to download the necessary TypeScript definition in settings and specified --module commonjs in the compiler settings. However, I keep running ...

Using either prop type for a React component in Typescript

Looking to build a Table component that can either render data from a prop or accept custom rendering via children. In order to achieve this, I need a type that can handle both scenarios with either data or children. I've come across some solutions a ...

Using NextJs <Script> is only effective after a page has been reloaded

Currently delving into the world of NextJS and encountering an issue with integrating a third-party ebay script onto one of my route pages. The script only seems to appear sporadically upon reloading the page. However, when navigating to the store page via ...

What could be causing my NextJS application to not recognize the _document.tsx file?

Seeking assistance in understanding why my _document.tsx is not loading properly within my nextJS application. My Attempts So Far I have been diligently following the NextJS documentation for creating a custom _document.js. Despite my efforts, I am unable ...

How to access nested JSON elements in Javascript without relying on the eval function

Below is a JSON that I am trying to access. { "orders": { "errorData": { "errors": { "error": [ { "code": "ERROR_01", "description": "API service is down" } ] } }, "status": " ...

Custom type declaration file in Typescript fails to function properly

I have searched through countless solutions to a similar issue, but none seem to work for me. I am attempting to utilize an npm package that lacks TypeScript type definitions, so I decided to create my own .d.ts file. However, every time I try, I encounter ...

Any suggestions for a more effective method of managing authentication in Angular2 rc3 besides using guards?

After upgrading to router 3.0.0-alpha.8, I encountered a hurdle with authentication in my existing Angular2 app. Previously, I handled login/authentication by extending the RouterOutlet with an AuthRouterOutletDirective. This allowed me to easily check if ...

Utilizing React Custom Hooks for Firestore Data Retrieval

I recently developed a React custom hook that interfaces with a Firestore database. I followed the guidelines provided on the Firebase website, but I encountered an issue upon re-rendering the component. After refreshing my app, the useEffect hook function ...

Is it feasible to bring in a Typescript file into an active ts-node REPL session?

I want to experiment with some Typescript code that I have written. Currently, I usually run ts-node my-file-name.ts to test it out. But I am interested in making this process more interactive, similar to the Python REPL where you can import modules and ...

The setting of the custom user agent in the Chrome Extension Manifest Version 3 is not functioning correctly

We currently have an extension that consists of only two files: manifest.json and background.js Despite the browser (Chrome version 112) not reporting any errors, we are facing an issue where the user agent is not being set to 'my-custom-user-agent&a ...

Angular2 form builder generating dynamic forms based on results of asynchronous calls

When creating my form, I encountered a challenge with passing the results of an asynchronous call to the form builder. This is what I have attempted: export class PerformInspectionPage implements OnInit { checklists: any; inspectionform: FormGroup; n ...

The typing library for Angular does not properly identify the JQueryStatic object

Encountered an issue with the Angular declaration file: Error TS2304: Cannot locate identifier 'JQueryStatic'. The typings for jQuery are installed and properly declare JQueryStatic as an interface. Looking for solutions to resolve this error. ...

Testing Angular - The Art of Mocking InjectionToken

I've been experimenting with testing an Angular service that manages SignalR connections, using the SignalR code as an InjectionToken. Check out the provider file below: // signalr-provider.ts import { InjectionToken } from '@angular/core&apos ...

Utilizing StyleFunctionProps within JavaScript for Chakra UI Enhancements

I need help figuring out how to implement StyleFunctionProps in my Chakra UI theme for my NextJS project. The documentation on Chakra's website provides an example in Typescript, but I am working with Javascript. Can someone guide me on adapting this ...

What is the best way to utilize v-model with an array of strings in a Vuex store when using v-for

Encountered an issue while trying to set a value in an Array within the Vuex Store: VueCompilerError: v-model cannot be used on v-for or v-slot scope variables because they are not writable. Seeking alternatives to achieve this without creating a local co ...

Do Prisma Migrations Require a Default Value?

I'm struggling with Prisma data modeling and have tried almost everything to resolve an error I keep getting. The error states that the table needs a default value even though I have already assigned it an ID. I attempted to remove the relation name, ...