handling 401 in angular, how does pipe work really?

ILIA BROUDNO

I am using Angular 14 and making a post request to my json server using the pattern like this:

myApiCall(data:any): Observable<any> {
  return this.http.post<any>(url, data).pipe(catchError(this.handleError));
}

( as specified in https://angular.io/guide/http)

And then wanted to add 401 (unauthorized) handling to handleError

so I added this block

  if (error.status===401){//UnAthorized
    this.router.navigate(['login']);
  }

to my handleError like so:

private handleError(error: HttpErrorResponse) {
  if (error.status===401){//UnAthorized
    this.router.navigate(['login']);
  }
...
  return throwError(
    () => new Error('Something bad happened; please try again later.')
  );

}

I can see in debugger that this.router.navigate(['login']); is hit, but it does not navigate to the login screen. same code does work in another place. The error in chrome console is :

ERROR TypeError: Cannot read properties of (has file and line see below for details) undefined (reading 'router')
    at handleError (line where this.router.navigate(['login']); is)
    at catchError.js:10:39
    at OperatorSubscriber._error (OperatorSubscriber.js:23:21)
    ...

The top in call stack in the error is the .subscribe after myApiCall...

So what happens to handleError when I call

this.router.navigate(['login']);

Does it cause a return? And if so what gets returned ?

UPDATE

After Igor's suggestion of adding

return of([]) 

AND declaring handleError with ()=>{} syntax instead of normal, it worked.

I wonder why the second part is needed. I still suspect it has something to do with how pipe works.

This works:

private handleError = (error: HttpErrorResponse) => { 
  if (error.status===401)//UnAthorized
  {
    this.router.navigate(['login']);
    return of([]);
  } 
  ...
  return throwError(
    () => new Error('Something bad happened; please try again later.')
  );  
}

This does not

private handleError(error: HttpErrorResponse){ 
  if (error.status===401)//UnAthorized
  {
    this.router.navigate(['login']);
    return of([]);
  } 
  ...
  return throwError(
    () => new Error('Something bad happened; please try again later.')
  );  
}

After this.router.navigate instead of hitting return, control is transferred to the caller that results in an error that mentions router.

Why?

Igor Cantele

Have you tried returning an observable from the catchError operator?
Rxjs needs it to continue piping and not throwing errors that may stop redirecting.
You can easily return it with the of operator:

myApiCall(data:any): Observable<any> {
  return this.http.post<any>(url, data).pipe(
    catchError((err) =>
        if (error.status===401){
          // Redirect if unhautorized
          this.router.navigate(['login']);
        }
        // after catchError the piping proceeds,
        // you should handle the case where the observable is EMPTY
        // (i.e. in this scenario an error occurred)
        return of(EMPTY)
    );
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related