Solution - Retry Operator
Solution
import { fromEvent, throwError } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { catchError, finalize, map, mergeMap, retry } from 'rxjs/operators';
/** The UserResponse represents the shape of the response from the API. */
interface UserResponse {
  data: {
    id: number;
    email: string;
    first_name: string;
    last_name: string;
    avatar: string;
  };
}
/** The random function returns a random integer inclusively between `min` and `max`. */
function random(max: number, min: number): number {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
const output = document.getElementById('output') as HTMLTextAreaElement;
const btn = document.getElementById('btn') as HTMLButtonElement;
fromEvent(btn, 'click')
  .pipe(
    map(() => random(10, 15)),
    mergeMap((id) =>
      ajax.getJSON<UserResponse>(`https://reqres.in/api/users/${id}`).pipe(
        map((response) => response.data),
        catchError((error) => {
          output.value += `\n\n${error.message}`;
          output.scrollTop = output.scrollHeight;
          return throwError(error);
        })
      )
    ),
    retry(4),
    finalize(() => {
      btn.classList.add('cursor-not-allowed');
      btn.classList.add('opacity-50');
    })
  )
  .subscribe({
    error: (e) => console.error('observer', e),
    next: (value) => {
      output.value += `\n\n${JSON.stringify(value, null, 2)}`;
      output.scrollTop = output.scrollHeight;
    },
    complete: () => console.log('complete')
  });
This was a fun exercise where we are bringing together multiple operators for error handling.
Let's review the code above:
- First, we use the 
fromEvent()operator to add an event listener to thebtnelement'sclickevent. - We then 
map()theMouseEventto a random integer between10and15. - Using the 
mergeMap()operator we merge the output of theajax.getJSON()Observable. When we have successfully fetched a user we use themap()operator to return the nesteddataproperty from theresponseobject. - When an error occurs with the network request the 
catchError()operator receives theerror. We update theoutputtextareavalueproperty with the error message, scroll the textarea to the bottom, and return a new Observable created by thethrowError()operator with theerrorvalue. - When an error notification occurs the 
retry()operator will prevent the error from being emitted to the Observer and completing the Observable. The use ofretry(4)with thecountargument set to4will allow for the click event Observable to retry four additional times. Once thecountis decremented to-1the error is emitted to the Observer. - Finally, we use the 
finalize()operator to disable thebtnelement.