I'm using Angular 2 and RxJS to retrieve data from my API layer. I have a base service that I've written to deal with HTTP requests. The following code does this within my service:
protected apiGet(uri: string): Observable<HttpMappedResponse<T>> {
return this.mapAndHandle<T>(this.http.get(uri));
}
private mapAndHandle<T>(observable: Observable<Response>): Observable<HttpMappedResponse<T>> {
const o = observable
.map(res => {
const data = res.json() || {};
const mappedResponse = new HttpMappedResponse<T>(res, data);
// Retrieve page information from HTTP headers
mappedResponse.pageInfo = new PageInfo(res.headers);
return mappedResponse;
})
.share();
o.subscribe(null, e => this.errorService.handleHttpResponse(e));
return o;
}
This works well and gives me all the data I need when I call apiGet()
. What I'm now trying to do is the following:
- Send a HTTP request
- If a 401 error with a particular string is returned:
- Send another request to a different URL
- Update another service
- Retry the original request
- (then probably add logic to handle possible infinite retries)
- Else
- Rethrow the original http error
- Capture error and handle it
I've tried using .catch(), .retryWhen(), .map() and .flatMapTo() with no success - closest I've got is the following:
enum HttpVerb {
Put,
Post,
Get,
Delete
}
private mapAndHandle<T>(uri: string, type: HttpVerb): Observable<HttpMappedResponse<T>> {
const restObservable = this.getRestObservable(uri, type);
const o = restObservable
.map(res => this.mapToHttpMappedResponse<T>(res))
.catch((error, sourceObservable) => {
const data = error.json() || {};
if (error.status === 401 && data.Message === 'Token expired') {
console.log('Retrying');
// Refresh the expired auth token
const refreshToken = this.authService.userData.RefreshToken;
console.log(refreshToken);
this.authService
.refresh(new RefreshRequestModel(refreshToken))
.subscribe(x => null);
// Retry original
return this
.getRestObservable(uri, type)
.map(x => this.mapToHttpMappedResponse(x));
}
throw error;
})
.share();
o.subscribe(null, e => {
this.errorService.handleHttpResponse(e);
});
return o;
}
private mapToHttpMappedResponse<T>(res: Response): HttpMappedResponse<T> {
console.log('Attempt ' + Date.now());
const data = res.json() || {};
const mappedResponse = new HttpMappedResponse<T>(res, data);
// Retrieve page information from HTTP headers
mappedResponse.pageInfo = new PageInfo(res.headers);
return mappedResponse;
}
But this doesn't give me the right results.
Is there an operator that I can use to do this? retryWhen() seems the most logical, but I just keep getting myself into a mess with RxJs!