Wait for token retrieval before http

448 Views Asked by At

I am trying to create a service for fetching data that will first make sure there is a valid token.

My code is this:

AccountService:

export class AccountService {

    private tokenUrl = 'api/account/authorize';  
    private _token: Token;

    constructor(
        private http: HttpClient) { }

    /** GET token information from the server */
    getToken(refresh: boolean): Observable<Token> {
        if (!!this._token && !refresh) {
            console.log('returning cached token', this._token);
            return of(this._token);
        }
        return new Observable(observer =>{
            this.http.post<Token>(this.tokenUrl, {})
            .pipe(
                tap(token => this._token = token),
                tap(token => observer.next(token)),
                catchError(this.handleError('getToken', null))
            );
        })
    }
}

I am also trying to cache the token received so i do not have to do the post every time the token is requested, unless it is explicitely requested.

InfoService:

@Injectable()
export class InfoService {

    private infoBaseUrl = 'api/info/';  // URL to web api
    private _selectionOptions: SelectionOptionsResult;

    constructor(
        private http: HttpClient,
        private accountService: AccountService) { }

    getfilterOptions(filters: SelectionOptionRequest): Observable<SelectionOptionsResult> {

        var tokenObservable = this.accountService.getToken(false);

        console.log('THIS SUCCESFULLY HITS');

        return tokenObservable.switchMap((token) => {

            console.log('THIS NEVER HITS');

            let httpParams = new HttpParams();
            Object.keys(filters).forEach(function (key) {
                httpParams = httpParams.append(key, filters[key]);
            });
            var httpOptions = {
                headers: new HttpHeaders({
                    'Content-Type': 'application/json',
                    authorization: 'Bearer ' + token.access_Token
                }),
                params: httpParams
            };  

            return this.http.get<SelectionOptionsResult>(this.infoBaseUrl + 'GetfilterOptions', httpOptions)
                .pipe(
                    tap(so => this._selectionOptions = so),
                    catchError(this.handleError('getfilterOptions', null))
                );

        })
    }
}

component

getfilterOptions(filters: SelectionOptionRequest): void {
    this.infoService.getfilterOptions(filters)
        .subscribe(so => this.filterOptions = so);
}

Though it does go into getFilterOptions, it never reaches the getToken. What am I missing?

2

There are 2 best solutions below

4
On

Angular uses "cold" observables (https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339). Therefore it will never be executed up until you subscribe to it. I believe if you'll slightly change your code to

var tokenObservable = this.accountService.getToken(false).subscribe(() => {});

Everything will start to work as expected. I'm like 99% sure in that , so let me know if it will not fix your code.

1
On

sorry ::glups:: Why not? (I don't know the function of observer.next(token))

return this.http.post<Token>(this.tokenUrl, {})
            .pipe(
                tap(token => this._token = token),
                catchError(this.handleError('getToken', null))
            );
        })