I have some code I'm migrating to RxJS 5.5, which already worked.
public getMentor(id: number): Observable<Employee> {
const url = `${this.employeeUrl}/${id}/mentor`;
return this.http
.get(url, this.authService.getOptionsWithToken())
.retryWhen(errors => {
return errors
.mergeMap(error => (error.status === 404) ? Observable.throw(error) : Observable.of(error))
.take(this.maxRetries);
})
.map(response => response.json() as Employee)
.catch(ErrorHandlerService.handleError);
}
In any case, if this request fails with 404, it's OK according to the business logic. Now, this would be a near equivalent in 5.5:
public getMentor(id: number): Observable<Employee> {
const url = `${this.employeeUrl}/${id}/mentor`;
return this.http.get<Employee>(url)
.pipe(
retryWhen(errors => {
console.log('errorInService', errors);
return errors.pipe(
mergeMap(error => (error.status === 404) ? _throw(error) : of(error)),
take(this.maxRetries)
)
}),
catchError(ErrorHandlerService.handleError)
);
}
Here, the flow gets interrupted because inside retryWhen, errors is now a Subject and I cannot extract the status as before.
this.employeeService.getMentor(this.mentee.id).subscribe(
mentor => {
this.existingMentor = mentor;
this.modalAddConfirmation(addConfirmation, mentee, form);
},
e => {
console.log('errorInMentor', e);
if (e.status === 404) {
// console.log('No mentor');
this.employeeService.putMentor(mentee.id, this.mentor)
.subscribe(() => this.mentees.push(mentee));
} else {
return null;
}
}
);
In the original caller, "e" is now a string which says Http failure response for http://localhost:8888/employees/1/mentor: 404 OK
instead of an object. Obviously, the putMentor()
call never gets made. I'm just learning so it's most likely I haven't understood fully the new pipeable operators.
At least this code is throwing an ErrorObservable, but on the caller end (errorInMentor
) it's still a string:
public getMentor(id: number): Observable<Employee> {
const url = `${this.employeeUrl}/${id}/mentor`;
return this.http.get<Employee>(url)
.pipe(
retryWhen(errors => {
return errors.pipe(
mergeMap(error => {
console.log('error MergeMap', error);
return error.status === 404 ? _throw(error) : of(error);
}),
take(this.maxRetries)
)
}),
catchError(ErrorHandlerService.handleError)
);
}
It turned out that the culprit was the ErrorHandlerService.handleError()
function. Previously it worked like this:
public static handleError(error: any): Promise<any> {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
Promises and Pipeable operators do not get along well, so I updated the code to this:
public static handleError(error: any): ErrorObservable {
console.error('An error occurred', error);
return ErrorObservable.create(error.message || error);
}
However I only needed an additional adjustment:
public static handleError(error: any): ErrorObservable {
console.error('An error occurred', error);
return ErrorObservable.create(error);
}
Don't know how I missed that until now.