Home > Enterprise >  RxJs zip operator, check which one throws an error and continue on condition?
RxJs zip operator, check which one throws an error and continue on condition?

Time:11-26

I've 2 api service calls that I zip into one observable:

const firstAPIrequest = this.firstApi.getData();
const secondAPIrequest = this.secondApi.getData();

const combined = zip(firstAPIrequest, secondAPIrequest);

I currently map these to return an array:

combined.pipe(
   map((res) => {
      return [res[0], res[1]) // just an example
   }
);

Then I use it as a subscription in a different component

combined.subscribe(
   (res) => this.handleData(res),
   (err) => {
      console.debug('Fetch failed', err);
   }
)

In this case, if one of the API request failed it will show an error, but I would like to check in between which one failed, for example; if request1 returned data and request2 failed I would still return the data from request1

I've tried catchError but I don't think I can get the data in this function

combined.pipe(
   catchError((err) => ...), // how would I catch the data before it throws an error?
   map((res) => {
      return [res[0], res[1]) // just an example
   }
);

CodePudding user response:

To handle errors from each source individually, the catchError must be piped into each of them individually. catchError must return an observable, so we'll use RxJS of function for it.

import { of, catchError } from 'rxjs';

const handleError = (error: any) => of({error: error});

const firstAPIrequest = this.firstApi.getData().pipe(
  catchError(this.handleError)
);
const secondAPIrequest = this.secondApi.getData().pipe(
  catchError(this.handleError)
);

const combined = zip(firstAPIrequest, secondAPIrequest);

Now in the subscription you could check if the response is valid or an error.

combined.subscribe(
  ([res1, res2]) => {
    if (!!res1.error && !!res2.error) {
      // both API calls threw error
    } else if (!!res1.error) {
      // `firstAPIrequest` threw error
    } else if (!!res2.error) {
      // `secondAPIrequest` threw error
    } else {
      // both returned responses
    }
  }
);

Note: this assumes the actual response doesn't contain a property error. If so replace the error property in the handleError function with something else.

CodePudding user response:

you have to catch error on both of the sources, because if you caught the error after combining, the combination stream stops after the first error. for example:

const replaceErrorWithNull = catchError(() => of(null));

const firstAPIrequest = this.firstApi.getData();
const secondAPIrequest = this.secondApi.getData();

const combined = zip(
  firstAPIrequest.pipe(replaceErrorWithNull), 
  secondAPIrequest.pipe(replaceErrorWithNull)
);

with this approach null will be in place of data from API that errored

  • Related