typescriptrxjs

How should I make series of API calls with the middle one needing time?


I need to make a series of calls to an API. Here is what should happen:

This is what I have so far, but it does not work and does not include the third call.

this.firstCall(formData)
  .pipe(
    interval(3000)
    .pipe(
      switchMap(res => {
        this.secondCall(res)
          .pipe(
            catchError(error => {
              return of(null);
            })
        )
      }),
      takeUntil(res => res.code !== 'P'),
      timeout(21000)
    )
  )
  .subscribe({
    next: (data) => {
      console.log('SUCCESS DATA', data)
    },
    error: (error) => {
      console.log('PROCESSING ERROR', error)
    }
  })

Solution

  • I like the elegance of the accepted answer, but for completeness sake, here's a version that doesn't require recursion which can be difficult to grok.

    import { of, first, repeat, mergeMap, switchMap, defer } from 'rxjs';
    
    let i = 0;
    const firstAPI$ = defer(() => of('123'));
    const secondAPI = (id: any) => defer(() => {
      console.log('second API called');
      i++;
      return i > 10 ? of({ code: 'C' }) : of({ code: 'P' });
    });
    const thirdAPI = (id: any) => of(`hello ${id}`);
    
    firstAPI$
      .pipe(
        switchMap((id: any) =>
          secondAPI(id).pipe(
            // Repeat the subscription to the second API every 500 millis
            repeat({delay: 500}),
            // Take the first non-P value
            first(({code}) => code !== 'P'),
            // Throw the error if the code is 'E' else run the third API
            mergeMap(val => {
              if (val.code === 'E') 
                throw new Error('Processing failed')
              else 
                return thirdAPI(id)
            })
          )
        )
      )
      .subscribe({
        next: (data: any) => {
          console.log('SUCCESS DATA', data);
        },
        error: (error: any) => {
          console.log('PROCESSING ERROR', error);
        },
      });