3

This is my error interceptor class. I need to throw error error to ccomponent class observable method: i haved checked throwError(error) is now deprecated, but there is no new Error(HttpErrorResponse)

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
    constructor(private toastr: ToastrService,private authService: AuthService,
        private router:Router) {
    }

    intercept( request: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> {
      return next.handle(request)
          .pipe(
              catchError((error: HttpErrorResponse) => {

                debugger
                  let message = '';
                  if (error.error instanceof ErrorEvent) {
                      // handle client-side error
                      message = `Error: ${error.error.message}`;
                      this.toastr.error(message);
                  } else {
                      // handle server-side error
                      debugger
                    
                      message = `Error: ${ error?.error?.Message || error?.statusText}`; 
                      if(!error.status)
                      {
                          this.toastr.error('Not able connect to server');                        
                      }

else if ([400].includes(error.status) && error.error?.Message === 'Session Expired') {

                     this.toastr.error("Session Expired");
                      this.authService.logout();
                     
                  }
                     .....

                    else if ([404].includes(error.status)) {
                      
                          this.router.navigate(['404']);  
                    }  
                   
                    else
                    {                  
                        this.toastr.error(message); 
                    } 
                  }
                 
                 return throwError(() => error) //If i throw errror like this it is coming error inteceptor agian
              })
          )
  }

}

component

getEditCollectionById(id:string)
  {
     debugger
     this.collectionService.getEditCollectionById(id).pipe(takeUntil(this.unsubscribe$)).subscribe({
       next: (result: any)  => {            
         if (result) {          
          
            this.collection=result;

         }
         else {
            this.close();
         }
       },
       error: (error:any) => {
           // If i throw error in interceptor it is not coming here
          this.goToDetail(this.collectionId);
       }
     });   

  }

service

getEditCollectionById(id: string): Observable<ICollection> {
          
      return  this.httpClient.get<Result<ICollection>>(baseUrl + '/Collection/GetEditCollectionById'+ `/${id}`) 
                  .pipe(map((res:any)=>{  res.data.valueDate = new Date(res.data.valueDate);       
                             return res.data;
                          })
                );
   }

i need to throw error in interceptor class. i am getting 400 error from server. i need show error message from interceptor class and i need to throw error to controller method.

EDIT:

Error Debug

enter image description here

EDIT: afer debugging infigured out its happening becuase of

 logout()  {
        
        debugger
        this.httpClient.post<any>(`${baseUrl}/Auth/revoke-token`, {}, { withCredentials: true })
        .subscribe(); 
             
        this.stopRefreshTokenTimer();
        this.setUserValue(null);
       this.router.navigate(['login']);
    }

Is there an update i need to do in this method?

2 Answers 2

6

If you want to pass an error to the component, and don't want to use state management to share an error response between classes, try tapping it in the interceptor like

import {
  HttpErrorResponse,
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    return next.handle(request).pipe(
      tap({
        next: () => null,
        error: (error: HttpErrorResponse) => {
          console.log(
            'the interceptor has caught an error, process it here',
            error
          );
        },
      })
    );
  }
}

another option is to use throwError

import {
  HttpErrorResponse,
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    return next.handle(request).pipe(
      catchError((error: HttpErrorResponse) => {
        console.warn(
          'the interceptor has caught an error, process it here',
          error
        );
        return throwError(() => error);
      })
    );
  }
}

import { HttpClient, HttpErrorResponse, HttpEvent } from '@angular/common/http';
import { Component, VERSION } from '@angular/core';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  public name = 'Angular ' + VERSION.major;

  public error?: HttpErrorResponse;

  constructor(private readonly http: HttpClient) {
    this.getData().subscribe();
  }

  public getData() {
    return this.http.get('xxx').pipe(
      catchError(
        (error: HttpErrorResponse, caught: Observable<HttpEvent<unknown>>) => {
          console.error(
            'the component has caught an error, process it here',
            error
          );
          this.error = error;
          return of();
        }
      )
    );
  }
}

<!-- the component template -->

<hello name="{{ name }}"></hello>
<div>Caught error: {{ error?.message }}</div>

<p>Start editing to see some magic happen :)</p>

enter image description here

see live here:

PS: how to handle error in the logout method

logout()  {
        this.httpClient.post<any>(`${baseUrl}/Auth/revoke-token`, {}, { withCredentials: true })
        .pipe(catchError(error => {
          // do something with the error here
          return of();
        }),
        tap(() => {
          this.stopRefreshTokenTimer();
          this.setUserValue(null);
          this.router.navigate(['login']);
        }))
        .subscribe();
    }
Sign up to request clarification or add additional context in comments.

13 Comments

Thanks .actullay i am using calling service methd from component..in my case what i have to change?
@Ajt please check my answer again, I have updated it. See postscript in the end of my comment.
Actually in previous version it was woring fine..is there any other option without tap method means using catchError
@Ajt I don't think so. When you use catchError and return a new error within it, or return the caught observable that errored, it will go circles. When you use the catchError operator you tell your code to stop processing an errored observable. So, you should use catchError only when you want to stop processing the error.
whether i can use this.router.navigate(['404']); within tap
|
1

Check on this sample code

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { tap } from 'rxjs/operators';
import { AccountService } from '../services/account.service';
import { AlertService } from '../services/alert.service';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
    constructor(private accountService: AccountService, private alertService: AlertService) {}

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(
            tap({
                next: () => null,
                error: (err: HttpErrorResponse) => {
                    if ([401, 403].includes(err.status) && this.accountService.signInResponse)
                        this.accountService.signOut(); // auto logout if 401 or 403 response returned from api

                    const error = err.error?.message || err.status;
                    this.alertService.error(error);
                    return throwError(error);
                },
            })
        );
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.