I'm new at using Angular and Rxjs.
Basically an app consumes an Api and needs to provide a valid authentication token. This token is short lived, and if it has expired it can be refreshed.
I wrote a specific http service which add the correct headers to every request and in case of authentication failure tries to refresh the token and retry.
Below is how I implemented it:
export class HttpAService extends Http {
constructor(
backEnd: XHRBackend,
options: RequestOptions,
private authenticationService: AuthenticationService
) {
super(backEnd, options);
// get an authentication token from an authentication service
let token = authenticationService.token;
options.headers.set('Authorization', `Bearer ${token}`);
}
private request1(
url: string | Request,
options?: RequestOptionsArgs
): Observable<Response> {
// get a token from an authentication service
let token = this.authenticationService.token;
// add it to the request headers
if (typeof url === 'string') {
if (!options) {
options = { headers: new Headers };
}
options.headers.set('Authorization', `Bearer ${token}`);
} else {
url.headers.set('Authorization', `Bearer ${token}`);
}
// make the request
return super.request(url, options);
}
public request(
url: string | Request,
options?: RequestOptionsArgs
): Observable<Response> {
// init retry flag
let retried: boolean = false;
// make the request and retry one time in case of failure
const obs = Observable.defer(() => this.request1(url, options));
return obs.retryWhen(attempt => {
// request failed
return attempt.flatMap(res => {
// if it's the first round and an authentication error try to refresh token
if ((!retried) && (500 === res.status) && ('Unauthenticated.' == res.json().message)) {
retried = true;
// refresh attempts to create a new token that can be retrieved using authenticationService.getToken.
return this.authenticationService.refresh();
}
return Observable.throw(res);
})
})
}
}
The problem I ran into was to have the new token used by the retry request (in other words to have the request1 function rerun during the retry). It seem that defer(...) did the trick.
I'd like to know if this implementation is correct and if there is a more elegant way to implement this behavior.
Thank you for your responses.