ILIA BROUDNO
ILIA BROUDNO

Reputation: 1893

handling 401 in angular, how does pipe work really?

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?

SECOND UPDATE:

Actually the first part (return of...) is not necessary to make it work, only the second (making it a lambda expression) is enough.

Upvotes: 0

Views: 102

Answers (1)

Igor Cantele
Igor Cantele

Reputation: 953

Try this:

myApiCall(data:any): Observable<any> {
  return this.http.post<any>(url, data).pipe(
    catchError((err) =>
        if (err.status===401){
          // Redirect if unhautorized
          this.router.navigate(['login']);
        }
        ...
    );
}

Note the lambda syntax of the error handler declaration. It is required in order to pass in the context (this). Without it the 'router' is not known hence the error. More details here

Upvotes: 1

Related Questions