I'm sending multiple API requests in my Angular (10) app. If one of the requests returns response with status 401 I would like to redirect the page to my login page (from the component page).
I have a service that responsible for API calls that has the following 2 methods :
export class ApiService {
constructor(private http: HttpClient){
}
public get<T>(path: string, params: HttpParams = new HttpParams(), headers: HttpHeaders = new HttpHeaders()): Observable<T> {
return this.getBodyOfResponseOrRedirect(
this.http.get<T>(path, {headers, params, observe: 'response'}));
}
private getBodyOfResponseOrRedirect<T>(responseObservable: Observable<HttpResponse<T>>): Observable<T> {
return responseObservable.pipe(map(response => {
if (response.status === 401) {
window.location.href = 'https://custom-url';
} else {
return response.body;
}
}));
}
Now I tried using the API service methods in another service:
export class ShopDataService{
...
getShopsData(): Observable<Shop[]> {
return this.apiService.get<Shop[]>("https://shops.com/v1/endpoint)
.pipe(
tap(data => console.log('shop recieved : ' + JSON.stringify(data))),
catchError(this.handleError)
);
}
private handleError(err: HttpErrorResponse) {
let errorMessage = '';
errorMessage = `Server returned code : ${err.status}, error message is : ${err.message}`;
console.error(errorMessage);
return throwError(errorMessage);
}
The redirect doesn't work when the response status is 401, instead I'm seeing in the console :
main.gb7558h03a743440f512.js:1 Server returned code : 401, error message is : Http failure response for https://shops.com/v1/endpoint: 401 OK
What am I doing wrong ?
The big idea here, is that when I load the component my auth token is valid. After some time, my token is expired but I didn't refresh or move to another page. Therefore, current page functionality might send api requests with an invalid token and will get 401 error in response. I would like to handle this behavior.
The 401 Unauthorized response is usually emitted as an error notification from the Angular HttpClient. So you'd need to use RxJS catchError operator to catch the error and redirect. You could then emit NEVER constant so that nothing emits after the redirect and keep the observable alive, or emit EMPTY constant to complete the observable.
Try the following
import { throwError, NEVER } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
export class ApiService {
constructor(private http: HttpClient) { }
public get<T>(
path: string,
params: HttpParams = new HttpParams(),
headers: HttpHeaders = new HttpHeaders()
): Observable<T> {
return this.getBodyOfResponseOrRedirect(
this.http.get<T>(path, {headers, params, observe: 'response'}));
}
private getBodyOfResponseOrRedirect<T>(
responseObservable: Observable<HttpResponse<T>>
): Observable<T> {
return responseObservable.pipe(
catchError(error => {
if (!!error.status && error.status === 401) {
window.location.href = 'https://custom-url';
return NEVER; // <-- never emit after the redirect
}
return throwError(error); // <-- pass on the error if it isn't 401
}),
map(response => response.body)
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With