angularinterceptorretrywhen

HTTP Request retry on particular error using interceptor and retrywhen


I have a service that makes a call to GET API and receives a response back. I have implemented HTTP Interceptor to properly and globally handle any errors though out the application. I want to do is, when my API returns a particular error, say for example, error 501, I need to retry that request for n no of times and t seconds of delay before every request. I also want to handle a generic error if my retries are over(i.e. if I get error on the last retry, I want to handle it in a particular way). Please help me figure out how to solve this issue.

This is all implemented using Angular 6, solution with correct syntax will be appreciated.

Thank you


Solution

  • You may consider doing this using retryWhen, delay, tap, scan of RxJS. Something like the following code where an Angular service invokes the Google APIs to authenticate a user in an app that doesn't run on a browser, for e.g. a desktop app. This service uses RxJS to retry the REST API calls at a specific interval in case of failure due to unstable internet connection:

    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { retryWhen, delay, tap, scan, concatMap } from 'rxjs/operators';
    
    @Injectable({
      providedIn: 'root'
    })
    export class GoogleDeviceAuthService {
    
      private readonly client_id = "<client-id>";
      private readonly client_secret = "<client-secret>";
    
      private readonly userCodeRequest = {
        "client_id": this.client_id,
        "scope": "email profile"
      };
    
      private readonly pollGoogleAuthServerRequestTemplate = {
        "client_id": this.client_id,
        "client_secret": this.client_secret,
        "code": "",
        "grant_type": "http://oauth.net/grant_type/device/1.0"
      }
    
      private readonly userCodeUrl = "https://accounts.google.com/o/oauth2/device/code";
    
      private readonly pollGoogleAuthServerUrl = "https://www.googleapis.com/oauth2/v4/token";
    
      constructor(private readonly http: HttpClient) { }
    
      public getUserCode() {
        return this.http.post(this.userCodeUrl, this.userCodeRequest)
          .pipe(
            retryWhen(err => err.pipe(
              scan(
                (retryCount, err) => {
                  if (retryCount > 3)
                    throw err;
                  else
                    return retryCount + 1;
                }, 0
              ),
              delay(1000),
              tap(err => console.log("Retrying...", err))
            )));
      }
    
      public checkAuthServerForUserInput(deviceCode) {
        let pollGoogleAuthServerRequest = { 
            ...this.pollGoogleAuthServerRequestTemplate, 
            ...{ "code": deviceCode } };
        return this.http.post(this.pollGoogleAuthServerUrl, pollGoogleAuthServerRequest)
          .pipe(
            retryWhen(err => err.pipe(
              scan(
                (retryCount, err) => {
                  if (retryCount > 3)
                    throw err;
                  else
                    return retryCount + 1;
                }, 0
              ),
              delay(1000),
              tap(err => console.log("Retrying...", err))
            )));;
      }
    }