How to subscribe to an observable from a function that returns observable?











up vote
0
down vote

favorite












So I have a put method that returns an observable, inside this method I need to check if the token is valid, if it is not valid, then I will need to call another method that can create a new refresh token and I need to subscribe to this method so that I can update the values of the local refresh token, and then return the observable for the put method.



This is what I have so far:



    public putRequest(endpoint: string, body: any):
Observable < APIResponseModel < any >> {
if (this.authService.isValidToken()) {
// . . .
}));
}
else {

// get a new token
const refresh = this.authService.refreshToken();

return refresh.switchMap(response => {

this.authService.setRefreshToken(response.results.refreshToken);

return this.httpClient.put < any > (`${endpoint}`, body).pipe(map(result => {
this.hideLoader();
return result;
}));
}).catch(err => {
console.log("error occurred! " + err)
this.authService.redirectToLogin();
return this.getNullResponse();
});

}


AuthService methods:



  isValidToken(): boolean {
const token = this.getAuthToken();
if (!token && this.firstload) {

return true; }
if (token && !this.firstload) {
if (this.jwtHelper.isTokenExpired(token)) {
console.log("Token is expired ");

return false;
} else {
return true;
}
} else {
return false;
}
}

refreshToken(): Observable<APIResponseModel<any>> {

console.log("refresh token:" + this.getRefreshToken());
const url = `${environment.baseAPIUrl}/${environment.version}/login/token/refresh`;
const body = {
refreshToken: `${this.getRefreshToken()}`
};
return this.httpClient.post(url, body).map((response: APIResponseModel<any>) => {
this.setAuthToken(response.results.token);
this.setRefreshToken(response.results.refreshToken);
this.tokenBeingRefreshed = false;
return response;
}, err => err);
}


Note that I tried SwitchMap and MergeMap but I am getting server error that the session is expired. Seems I am getting this error before waiting to generate a new token. How can I make sure a new token is created before calling the httpClient.put ?










share|improve this question
























  • Can you add the relevant authService functions to your question please?
    – user184994
    Nov 8 at 11:44










  • Yes I just added them now.
    – Wael
    Nov 8 at 11:48















up vote
0
down vote

favorite












So I have a put method that returns an observable, inside this method I need to check if the token is valid, if it is not valid, then I will need to call another method that can create a new refresh token and I need to subscribe to this method so that I can update the values of the local refresh token, and then return the observable for the put method.



This is what I have so far:



    public putRequest(endpoint: string, body: any):
Observable < APIResponseModel < any >> {
if (this.authService.isValidToken()) {
// . . .
}));
}
else {

// get a new token
const refresh = this.authService.refreshToken();

return refresh.switchMap(response => {

this.authService.setRefreshToken(response.results.refreshToken);

return this.httpClient.put < any > (`${endpoint}`, body).pipe(map(result => {
this.hideLoader();
return result;
}));
}).catch(err => {
console.log("error occurred! " + err)
this.authService.redirectToLogin();
return this.getNullResponse();
});

}


AuthService methods:



  isValidToken(): boolean {
const token = this.getAuthToken();
if (!token && this.firstload) {

return true; }
if (token && !this.firstload) {
if (this.jwtHelper.isTokenExpired(token)) {
console.log("Token is expired ");

return false;
} else {
return true;
}
} else {
return false;
}
}

refreshToken(): Observable<APIResponseModel<any>> {

console.log("refresh token:" + this.getRefreshToken());
const url = `${environment.baseAPIUrl}/${environment.version}/login/token/refresh`;
const body = {
refreshToken: `${this.getRefreshToken()}`
};
return this.httpClient.post(url, body).map((response: APIResponseModel<any>) => {
this.setAuthToken(response.results.token);
this.setRefreshToken(response.results.refreshToken);
this.tokenBeingRefreshed = false;
return response;
}, err => err);
}


Note that I tried SwitchMap and MergeMap but I am getting server error that the session is expired. Seems I am getting this error before waiting to generate a new token. How can I make sure a new token is created before calling the httpClient.put ?










share|improve this question
























  • Can you add the relevant authService functions to your question please?
    – user184994
    Nov 8 at 11:44










  • Yes I just added them now.
    – Wael
    Nov 8 at 11:48













up vote
0
down vote

favorite









up vote
0
down vote

favorite











So I have a put method that returns an observable, inside this method I need to check if the token is valid, if it is not valid, then I will need to call another method that can create a new refresh token and I need to subscribe to this method so that I can update the values of the local refresh token, and then return the observable for the put method.



This is what I have so far:



    public putRequest(endpoint: string, body: any):
Observable < APIResponseModel < any >> {
if (this.authService.isValidToken()) {
// . . .
}));
}
else {

// get a new token
const refresh = this.authService.refreshToken();

return refresh.switchMap(response => {

this.authService.setRefreshToken(response.results.refreshToken);

return this.httpClient.put < any > (`${endpoint}`, body).pipe(map(result => {
this.hideLoader();
return result;
}));
}).catch(err => {
console.log("error occurred! " + err)
this.authService.redirectToLogin();
return this.getNullResponse();
});

}


AuthService methods:



  isValidToken(): boolean {
const token = this.getAuthToken();
if (!token && this.firstload) {

return true; }
if (token && !this.firstload) {
if (this.jwtHelper.isTokenExpired(token)) {
console.log("Token is expired ");

return false;
} else {
return true;
}
} else {
return false;
}
}

refreshToken(): Observable<APIResponseModel<any>> {

console.log("refresh token:" + this.getRefreshToken());
const url = `${environment.baseAPIUrl}/${environment.version}/login/token/refresh`;
const body = {
refreshToken: `${this.getRefreshToken()}`
};
return this.httpClient.post(url, body).map((response: APIResponseModel<any>) => {
this.setAuthToken(response.results.token);
this.setRefreshToken(response.results.refreshToken);
this.tokenBeingRefreshed = false;
return response;
}, err => err);
}


Note that I tried SwitchMap and MergeMap but I am getting server error that the session is expired. Seems I am getting this error before waiting to generate a new token. How can I make sure a new token is created before calling the httpClient.put ?










share|improve this question















So I have a put method that returns an observable, inside this method I need to check if the token is valid, if it is not valid, then I will need to call another method that can create a new refresh token and I need to subscribe to this method so that I can update the values of the local refresh token, and then return the observable for the put method.



This is what I have so far:



    public putRequest(endpoint: string, body: any):
Observable < APIResponseModel < any >> {
if (this.authService.isValidToken()) {
// . . .
}));
}
else {

// get a new token
const refresh = this.authService.refreshToken();

return refresh.switchMap(response => {

this.authService.setRefreshToken(response.results.refreshToken);

return this.httpClient.put < any > (`${endpoint}`, body).pipe(map(result => {
this.hideLoader();
return result;
}));
}).catch(err => {
console.log("error occurred! " + err)
this.authService.redirectToLogin();
return this.getNullResponse();
});

}


AuthService methods:



  isValidToken(): boolean {
const token = this.getAuthToken();
if (!token && this.firstload) {

return true; }
if (token && !this.firstload) {
if (this.jwtHelper.isTokenExpired(token)) {
console.log("Token is expired ");

return false;
} else {
return true;
}
} else {
return false;
}
}

refreshToken(): Observable<APIResponseModel<any>> {

console.log("refresh token:" + this.getRefreshToken());
const url = `${environment.baseAPIUrl}/${environment.version}/login/token/refresh`;
const body = {
refreshToken: `${this.getRefreshToken()}`
};
return this.httpClient.post(url, body).map((response: APIResponseModel<any>) => {
this.setAuthToken(response.results.token);
this.setRefreshToken(response.results.refreshToken);
this.tokenBeingRefreshed = false;
return response;
}, err => err);
}


Note that I tried SwitchMap and MergeMap but I am getting server error that the session is expired. Seems I am getting this error before waiting to generate a new token. How can I make sure a new token is created before calling the httpClient.put ?







angular typescript rxjs observable switchmap






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 8 at 11:48

























asked Nov 8 at 11:40









Wael

57411026




57411026












  • Can you add the relevant authService functions to your question please?
    – user184994
    Nov 8 at 11:44










  • Yes I just added them now.
    – Wael
    Nov 8 at 11:48


















  • Can you add the relevant authService functions to your question please?
    – user184994
    Nov 8 at 11:44










  • Yes I just added them now.
    – Wael
    Nov 8 at 11:48
















Can you add the relevant authService functions to your question please?
– user184994
Nov 8 at 11:44




Can you add the relevant authService functions to your question please?
– user184994
Nov 8 at 11:44












Yes I just added them now.
– Wael
Nov 8 at 11:48




Yes I just added them now.
– Wael
Nov 8 at 11:48












2 Answers
2






active

oldest

votes

















up vote
0
down vote













So if i got your issue correctly it is




  • PUT

  • if (!token) → GET(token)

  • retry PUT


In this case, the correct flow would be



getData() {
return this.http.put(...);
}

getToken() {
return this.http.get(...);
}

isValidToken() {
return ...;
}

securedCall() {
const data$ = this.isValidToken ?
this.getData() :
this.getToken().pipe(
switchMap(token => this.getData())
);

return data$;
}


Way cleanier and easier to read than using operators !






share|improve this answer




























    up vote
    0
    down vote













    Don't worry to make sure refresh token before any http request in server, but use Http Interceptor when you are making a request in server set token in request header and check it in server-side if token has expire or signature is not valid or anything else is wrong set response header status 401 and use catchError to catch error and check if status is 401 then call refresh token method that is going to send a request in server to refresh token using switchMap as example below:



    here is httpInterceptor



    export class HttpInterceptorService implements HttpInterceptor {

    constructor(private auth : AuthService ) { }

    isRefreshingToken: boolean = false;

    tokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

    intercept(request: HttpRequest<any>, next: HttpHandler) : Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any> | any> {

    if( this.auth.token ) {

    if( this.isRefreshingToken ){ // next handle when make request to refresh token .........

    return next.handle(this.setRequestHeaders( request ));

    }else{ // request and catch Error when token is expired or any else Error ...........

    return next.handle(this.setRequestHeaders( request ))
    .pipe(
    catchError(err => { // catch response error from server
    if (err instanceof HttpErrorResponse) {
    switch ((<HttpErrorResponse>err).status) {
    case 401: // if is 401 error
    return this.handle401Error(request, next); // return handle401Error method
    }
    } else {
    return throwError(err);
    }
    })
    );

    }

    }else{
    return next.handle(this.setRequestHeaders( request ))
    }

    private setRequestHeaders(request: HttpRequest<any> ) : HttpRequest<any> { // set request headers ......

    if( this.isRefreshingToken ){

    return request.clone({headers :request.headers.set('Refresh-Token',this.auth.refresh_token || '')});

    }

    else if( this.auth.token ){

    return request.clone({headers :request.headers.set('Token', this.auth.token || '' ) });

    }
    }

    private handle401Error(request: HttpRequest<any>, next: HttpHandler) { // 401 error from server when token is expired ..

    if (!this.isRefreshingToken) {

    this.isRefreshingToken = true;
    // Reset here so that the following requests wait until the token
    // comes back from the refreshToken call.

    this.tokenSubject.next(null);

    return this.auth.refreshToken(clientSignature) // make request to refresh token return false or new token and new refresh token

    .pipe( // get result from refresh token ............................

    switchMap((result: any) => {

    if ( result ) {

    this.isRefreshingToken = false;

    this.auth.refresh_tokens( result );

    this.tokenSubject.next( result );

    return next.handle(this.setRequestHeaders( request ) );
    }

    this.isRefreshingToken = false;

    this.auth.logout();

    this.tokenSubject.next(false);

    return next.handle(request);
    }),
    catchError( err => {

    this.isRefreshingToken = false;

    this.auth.logout();

    this.tokenSubject.next(false);

    return next.handle(request);

    } ),

    finalize(() => {
    this.isRefreshingToken = false;
    }),
    );

    } else {
    return this.tokenSubject
    .pipe(filter(token => token != null),
    take(1),
    switchMap( token => {

    if( token ){

    return next.handle(this.setRequestHeaders( request ));

    }else{
    return next.handle(request);
    }

    })
    );
    }
    }
    }


    provide http interceptor in app.module:



    providers: [

    {
    provide:HTTP_INTERCEPTORS,

    useClass:HttpInterceptorService,

    multi:true

    }
    ]





    share|improve this answer





















      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53207011%2fhow-to-subscribe-to-an-observable-from-a-function-that-returns-observable%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      0
      down vote













      So if i got your issue correctly it is




      • PUT

      • if (!token) → GET(token)

      • retry PUT


      In this case, the correct flow would be



      getData() {
      return this.http.put(...);
      }

      getToken() {
      return this.http.get(...);
      }

      isValidToken() {
      return ...;
      }

      securedCall() {
      const data$ = this.isValidToken ?
      this.getData() :
      this.getToken().pipe(
      switchMap(token => this.getData())
      );

      return data$;
      }


      Way cleanier and easier to read than using operators !






      share|improve this answer

























        up vote
        0
        down vote













        So if i got your issue correctly it is




        • PUT

        • if (!token) → GET(token)

        • retry PUT


        In this case, the correct flow would be



        getData() {
        return this.http.put(...);
        }

        getToken() {
        return this.http.get(...);
        }

        isValidToken() {
        return ...;
        }

        securedCall() {
        const data$ = this.isValidToken ?
        this.getData() :
        this.getToken().pipe(
        switchMap(token => this.getData())
        );

        return data$;
        }


        Way cleanier and easier to read than using operators !






        share|improve this answer























          up vote
          0
          down vote










          up vote
          0
          down vote









          So if i got your issue correctly it is




          • PUT

          • if (!token) → GET(token)

          • retry PUT


          In this case, the correct flow would be



          getData() {
          return this.http.put(...);
          }

          getToken() {
          return this.http.get(...);
          }

          isValidToken() {
          return ...;
          }

          securedCall() {
          const data$ = this.isValidToken ?
          this.getData() :
          this.getToken().pipe(
          switchMap(token => this.getData())
          );

          return data$;
          }


          Way cleanier and easier to read than using operators !






          share|improve this answer












          So if i got your issue correctly it is




          • PUT

          • if (!token) → GET(token)

          • retry PUT


          In this case, the correct flow would be



          getData() {
          return this.http.put(...);
          }

          getToken() {
          return this.http.get(...);
          }

          isValidToken() {
          return ...;
          }

          securedCall() {
          const data$ = this.isValidToken ?
          this.getData() :
          this.getToken().pipe(
          switchMap(token => this.getData())
          );

          return data$;
          }


          Way cleanier and easier to read than using operators !







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 8 at 12:24









          trichetriche

          24.4k42050




          24.4k42050
























              up vote
              0
              down vote













              Don't worry to make sure refresh token before any http request in server, but use Http Interceptor when you are making a request in server set token in request header and check it in server-side if token has expire or signature is not valid or anything else is wrong set response header status 401 and use catchError to catch error and check if status is 401 then call refresh token method that is going to send a request in server to refresh token using switchMap as example below:



              here is httpInterceptor



              export class HttpInterceptorService implements HttpInterceptor {

              constructor(private auth : AuthService ) { }

              isRefreshingToken: boolean = false;

              tokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

              intercept(request: HttpRequest<any>, next: HttpHandler) : Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any> | any> {

              if( this.auth.token ) {

              if( this.isRefreshingToken ){ // next handle when make request to refresh token .........

              return next.handle(this.setRequestHeaders( request ));

              }else{ // request and catch Error when token is expired or any else Error ...........

              return next.handle(this.setRequestHeaders( request ))
              .pipe(
              catchError(err => { // catch response error from server
              if (err instanceof HttpErrorResponse) {
              switch ((<HttpErrorResponse>err).status) {
              case 401: // if is 401 error
              return this.handle401Error(request, next); // return handle401Error method
              }
              } else {
              return throwError(err);
              }
              })
              );

              }

              }else{
              return next.handle(this.setRequestHeaders( request ))
              }

              private setRequestHeaders(request: HttpRequest<any> ) : HttpRequest<any> { // set request headers ......

              if( this.isRefreshingToken ){

              return request.clone({headers :request.headers.set('Refresh-Token',this.auth.refresh_token || '')});

              }

              else if( this.auth.token ){

              return request.clone({headers :request.headers.set('Token', this.auth.token || '' ) });

              }
              }

              private handle401Error(request: HttpRequest<any>, next: HttpHandler) { // 401 error from server when token is expired ..

              if (!this.isRefreshingToken) {

              this.isRefreshingToken = true;
              // Reset here so that the following requests wait until the token
              // comes back from the refreshToken call.

              this.tokenSubject.next(null);

              return this.auth.refreshToken(clientSignature) // make request to refresh token return false or new token and new refresh token

              .pipe( // get result from refresh token ............................

              switchMap((result: any) => {

              if ( result ) {

              this.isRefreshingToken = false;

              this.auth.refresh_tokens( result );

              this.tokenSubject.next( result );

              return next.handle(this.setRequestHeaders( request ) );
              }

              this.isRefreshingToken = false;

              this.auth.logout();

              this.tokenSubject.next(false);

              return next.handle(request);
              }),
              catchError( err => {

              this.isRefreshingToken = false;

              this.auth.logout();

              this.tokenSubject.next(false);

              return next.handle(request);

              } ),

              finalize(() => {
              this.isRefreshingToken = false;
              }),
              );

              } else {
              return this.tokenSubject
              .pipe(filter(token => token != null),
              take(1),
              switchMap( token => {

              if( token ){

              return next.handle(this.setRequestHeaders( request ));

              }else{
              return next.handle(request);
              }

              })
              );
              }
              }
              }


              provide http interceptor in app.module:



              providers: [

              {
              provide:HTTP_INTERCEPTORS,

              useClass:HttpInterceptorService,

              multi:true

              }
              ]





              share|improve this answer

























                up vote
                0
                down vote













                Don't worry to make sure refresh token before any http request in server, but use Http Interceptor when you are making a request in server set token in request header and check it in server-side if token has expire or signature is not valid or anything else is wrong set response header status 401 and use catchError to catch error and check if status is 401 then call refresh token method that is going to send a request in server to refresh token using switchMap as example below:



                here is httpInterceptor



                export class HttpInterceptorService implements HttpInterceptor {

                constructor(private auth : AuthService ) { }

                isRefreshingToken: boolean = false;

                tokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

                intercept(request: HttpRequest<any>, next: HttpHandler) : Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any> | any> {

                if( this.auth.token ) {

                if( this.isRefreshingToken ){ // next handle when make request to refresh token .........

                return next.handle(this.setRequestHeaders( request ));

                }else{ // request and catch Error when token is expired or any else Error ...........

                return next.handle(this.setRequestHeaders( request ))
                .pipe(
                catchError(err => { // catch response error from server
                if (err instanceof HttpErrorResponse) {
                switch ((<HttpErrorResponse>err).status) {
                case 401: // if is 401 error
                return this.handle401Error(request, next); // return handle401Error method
                }
                } else {
                return throwError(err);
                }
                })
                );

                }

                }else{
                return next.handle(this.setRequestHeaders( request ))
                }

                private setRequestHeaders(request: HttpRequest<any> ) : HttpRequest<any> { // set request headers ......

                if( this.isRefreshingToken ){

                return request.clone({headers :request.headers.set('Refresh-Token',this.auth.refresh_token || '')});

                }

                else if( this.auth.token ){

                return request.clone({headers :request.headers.set('Token', this.auth.token || '' ) });

                }
                }

                private handle401Error(request: HttpRequest<any>, next: HttpHandler) { // 401 error from server when token is expired ..

                if (!this.isRefreshingToken) {

                this.isRefreshingToken = true;
                // Reset here so that the following requests wait until the token
                // comes back from the refreshToken call.

                this.tokenSubject.next(null);

                return this.auth.refreshToken(clientSignature) // make request to refresh token return false or new token and new refresh token

                .pipe( // get result from refresh token ............................

                switchMap((result: any) => {

                if ( result ) {

                this.isRefreshingToken = false;

                this.auth.refresh_tokens( result );

                this.tokenSubject.next( result );

                return next.handle(this.setRequestHeaders( request ) );
                }

                this.isRefreshingToken = false;

                this.auth.logout();

                this.tokenSubject.next(false);

                return next.handle(request);
                }),
                catchError( err => {

                this.isRefreshingToken = false;

                this.auth.logout();

                this.tokenSubject.next(false);

                return next.handle(request);

                } ),

                finalize(() => {
                this.isRefreshingToken = false;
                }),
                );

                } else {
                return this.tokenSubject
                .pipe(filter(token => token != null),
                take(1),
                switchMap( token => {

                if( token ){

                return next.handle(this.setRequestHeaders( request ));

                }else{
                return next.handle(request);
                }

                })
                );
                }
                }
                }


                provide http interceptor in app.module:



                providers: [

                {
                provide:HTTP_INTERCEPTORS,

                useClass:HttpInterceptorService,

                multi:true

                }
                ]





                share|improve this answer























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  Don't worry to make sure refresh token before any http request in server, but use Http Interceptor when you are making a request in server set token in request header and check it in server-side if token has expire or signature is not valid or anything else is wrong set response header status 401 and use catchError to catch error and check if status is 401 then call refresh token method that is going to send a request in server to refresh token using switchMap as example below:



                  here is httpInterceptor



                  export class HttpInterceptorService implements HttpInterceptor {

                  constructor(private auth : AuthService ) { }

                  isRefreshingToken: boolean = false;

                  tokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

                  intercept(request: HttpRequest<any>, next: HttpHandler) : Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any> | any> {

                  if( this.auth.token ) {

                  if( this.isRefreshingToken ){ // next handle when make request to refresh token .........

                  return next.handle(this.setRequestHeaders( request ));

                  }else{ // request and catch Error when token is expired or any else Error ...........

                  return next.handle(this.setRequestHeaders( request ))
                  .pipe(
                  catchError(err => { // catch response error from server
                  if (err instanceof HttpErrorResponse) {
                  switch ((<HttpErrorResponse>err).status) {
                  case 401: // if is 401 error
                  return this.handle401Error(request, next); // return handle401Error method
                  }
                  } else {
                  return throwError(err);
                  }
                  })
                  );

                  }

                  }else{
                  return next.handle(this.setRequestHeaders( request ))
                  }

                  private setRequestHeaders(request: HttpRequest<any> ) : HttpRequest<any> { // set request headers ......

                  if( this.isRefreshingToken ){

                  return request.clone({headers :request.headers.set('Refresh-Token',this.auth.refresh_token || '')});

                  }

                  else if( this.auth.token ){

                  return request.clone({headers :request.headers.set('Token', this.auth.token || '' ) });

                  }
                  }

                  private handle401Error(request: HttpRequest<any>, next: HttpHandler) { // 401 error from server when token is expired ..

                  if (!this.isRefreshingToken) {

                  this.isRefreshingToken = true;
                  // Reset here so that the following requests wait until the token
                  // comes back from the refreshToken call.

                  this.tokenSubject.next(null);

                  return this.auth.refreshToken(clientSignature) // make request to refresh token return false or new token and new refresh token

                  .pipe( // get result from refresh token ............................

                  switchMap((result: any) => {

                  if ( result ) {

                  this.isRefreshingToken = false;

                  this.auth.refresh_tokens( result );

                  this.tokenSubject.next( result );

                  return next.handle(this.setRequestHeaders( request ) );
                  }

                  this.isRefreshingToken = false;

                  this.auth.logout();

                  this.tokenSubject.next(false);

                  return next.handle(request);
                  }),
                  catchError( err => {

                  this.isRefreshingToken = false;

                  this.auth.logout();

                  this.tokenSubject.next(false);

                  return next.handle(request);

                  } ),

                  finalize(() => {
                  this.isRefreshingToken = false;
                  }),
                  );

                  } else {
                  return this.tokenSubject
                  .pipe(filter(token => token != null),
                  take(1),
                  switchMap( token => {

                  if( token ){

                  return next.handle(this.setRequestHeaders( request ));

                  }else{
                  return next.handle(request);
                  }

                  })
                  );
                  }
                  }
                  }


                  provide http interceptor in app.module:



                  providers: [

                  {
                  provide:HTTP_INTERCEPTORS,

                  useClass:HttpInterceptorService,

                  multi:true

                  }
                  ]





                  share|improve this answer












                  Don't worry to make sure refresh token before any http request in server, but use Http Interceptor when you are making a request in server set token in request header and check it in server-side if token has expire or signature is not valid or anything else is wrong set response header status 401 and use catchError to catch error and check if status is 401 then call refresh token method that is going to send a request in server to refresh token using switchMap as example below:



                  here is httpInterceptor



                  export class HttpInterceptorService implements HttpInterceptor {

                  constructor(private auth : AuthService ) { }

                  isRefreshingToken: boolean = false;

                  tokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

                  intercept(request: HttpRequest<any>, next: HttpHandler) : Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any> | any> {

                  if( this.auth.token ) {

                  if( this.isRefreshingToken ){ // next handle when make request to refresh token .........

                  return next.handle(this.setRequestHeaders( request ));

                  }else{ // request and catch Error when token is expired or any else Error ...........

                  return next.handle(this.setRequestHeaders( request ))
                  .pipe(
                  catchError(err => { // catch response error from server
                  if (err instanceof HttpErrorResponse) {
                  switch ((<HttpErrorResponse>err).status) {
                  case 401: // if is 401 error
                  return this.handle401Error(request, next); // return handle401Error method
                  }
                  } else {
                  return throwError(err);
                  }
                  })
                  );

                  }

                  }else{
                  return next.handle(this.setRequestHeaders( request ))
                  }

                  private setRequestHeaders(request: HttpRequest<any> ) : HttpRequest<any> { // set request headers ......

                  if( this.isRefreshingToken ){

                  return request.clone({headers :request.headers.set('Refresh-Token',this.auth.refresh_token || '')});

                  }

                  else if( this.auth.token ){

                  return request.clone({headers :request.headers.set('Token', this.auth.token || '' ) });

                  }
                  }

                  private handle401Error(request: HttpRequest<any>, next: HttpHandler) { // 401 error from server when token is expired ..

                  if (!this.isRefreshingToken) {

                  this.isRefreshingToken = true;
                  // Reset here so that the following requests wait until the token
                  // comes back from the refreshToken call.

                  this.tokenSubject.next(null);

                  return this.auth.refreshToken(clientSignature) // make request to refresh token return false or new token and new refresh token

                  .pipe( // get result from refresh token ............................

                  switchMap((result: any) => {

                  if ( result ) {

                  this.isRefreshingToken = false;

                  this.auth.refresh_tokens( result );

                  this.tokenSubject.next( result );

                  return next.handle(this.setRequestHeaders( request ) );
                  }

                  this.isRefreshingToken = false;

                  this.auth.logout();

                  this.tokenSubject.next(false);

                  return next.handle(request);
                  }),
                  catchError( err => {

                  this.isRefreshingToken = false;

                  this.auth.logout();

                  this.tokenSubject.next(false);

                  return next.handle(request);

                  } ),

                  finalize(() => {
                  this.isRefreshingToken = false;
                  }),
                  );

                  } else {
                  return this.tokenSubject
                  .pipe(filter(token => token != null),
                  take(1),
                  switchMap( token => {

                  if( token ){

                  return next.handle(this.setRequestHeaders( request ));

                  }else{
                  return next.handle(request);
                  }

                  })
                  );
                  }
                  }
                  }


                  provide http interceptor in app.module:



                  providers: [

                  {
                  provide:HTTP_INTERCEPTORS,

                  useClass:HttpInterceptorService,

                  multi:true

                  }
                  ]






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 8 at 13:13









                  Klodian shaba

                  211112




                  211112






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53207011%2fhow-to-subscribe-to-an-observable-from-a-function-that-returns-observable%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      這個網誌中的熱門文章

                      Xamarin.form Move up view when keyboard appear

                      Post-Redirect-Get with Spring WebFlux and Thymeleaf

                      Anylogic : not able to use stopDelay()