Search code examples
angularrxjsangular-httpclientangular-http-interceptorsrxjs-observables

RXJS/Angular Replace Observable


In an angular interceptor, I want to check wether an auth-token exists. If not, it should be refreshed and the request should be resent.

return next.handle(authReq).pipe(map((result: any) => {
  if (result.body && result.body.error) {
    if (result.body.error === 'ERR_TOKEN_EXPIRED' || result.body.error === 'ERR_TOKENS_DO_NOT_MATCH') {
      console.log('Token is expired or invalid, refreshing.', result.body.error);

      return this.userService.refreshLoginToken().subscribe(success => {
        if (success) {
          return this.intercept(req, next);
        }
      });
    }
  }
  return result;
}));

The Problem is that I don't know how to replace the original Observable returned by next.handle() with a new one. The return statement before this.userService.refreshLoginToken().subscribe() returns a Subscription object. If I just pipe the result of refreshLoginToken() it wont work because refreshLoginToken sends an httprequest which is only executed when there is a subscription.

To reduce the question to a single line: How can I replace the Observable returned in line 1 by next.handle() with the one returned by this.intercept(req, next)?

Thank you!


Solution

  • I think you should do that a bit different way.

    please check the example below and the latest switchMap:

    import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
    import {Injectable} from '@angular/core';
    import {StoreState} from '@core/store';
    import {select, Store} from '@ngrx/store';
    import {getAuthToken} from '@v2/core/store/auth/auth.reducer';
    import {iif, Observable, of} from 'rxjs';
    import {switchMap, take} from 'rxjs/operators';
    
    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
        constructor(protected readonly store: Store<StoreState>) {}
    
        public intercept(request: HttpRequest<void>, next: HttpHandler): Observable<HttpEvent<void>> {
            return this.store.pipe(
                select(getAuthToken),
                take(1),
                switchMap(token =>
                    iif(
                        () => !token,
                        of(request),
                        of(
                            request.clone({
                                setHeaders: {
                                    Authorization: `Bearer ${token?.accessToken}`,
                                },
                            }),
                        ),
                    ),
                ),
                switchMap(clonedRequest => next.handle(clonedRequest)),
            );
        }
    }