I was asked to modify an existing angular http interceptor, specifically to add a logic to show an error in the developer console when the request to an API fails.
After reading some articles about it, I read that using pipe
combined with tap
on the response I could use catchError
to show it.
That part is working but it seems that the pipeline is being affected because even though I am returning an Observable
of the error on the catchError
function, that value is not being returned to the receiving end of this pipeline (i.e. when a subscribe is being used on an API call)
Here is the relevant code of the interceptor that I have.
What am I doing wrong that is affecting the pipeline ? why is the existing code not receiving the errors even though I am returning them.
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (!this.isRefreshingToken) {
// not relevant logic
}
const reqCopy = this.addHeaderToRequest(req);
// continue the request flow and tap into the response
return next.handle(reqCopy).pipe(
tap(evt => {
if (evt instanceof HttpResponse) {
if (evt.status === 500) {
console.log(">>", evt.body);
}
}
}),
catchError((err: any) => {
/* in case a special logic is neeeded for HttpErrorResponse
if(err instanceof HttpErrorResponse) {
}
*/
console.error(err) ;
if(!!err.error) {
console.error(JSON.stringify(err.error));
}
// return an observable of the error as required by the pipeline
return of(err);
})
);
}
Here is the code of a call to the API that used to work, meaning that the //login failed logic was executed when a error was received when calling the backend, but now that logic is not being executed, for this and for many other api calls.
this.service.login(this.model).subscribe(
// login successful
() => {
//not relevant code
},
// login failed
error => {
this.ssoService.init();
console.log("Login error: ", error);
switch (error.originalError.status) {
case 307:
// need password change
break;
case 400:
this.notificationService.showError(
NotificationMessages.LoginUserOrPasswordIncorrect
);
break;
case 423:
this.error = NotificationMessages.LoginAccountLocked;
break;
case 404:
this.notificationService.showError(
NotificationMessages.LoginUserOrPasswordIncorrect
);
break;
default:
break;
}
In the intercept function , you are returning next.handle(reqCopy).pipe(
, which is not a type of Observable<HttpEvent<any>>
.
you need to handle in following way.
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const reqCopy = req;
// continue the request flow and tap into the response
const event = next.handle(reqCopy);
event.pipe(
tap(evt => {
// ... your code
}),
catchError((err: any) => {
//....... your code
return of(err);
})
);
return event;
}
Here is the demo - https://stackblitz.com/edit/angular-interceptors-8aygw4
Hope this helps.