Angular interceptor: executing asynchronous tasks

My implementation includes an interceptor that acts as a retry wrapper for expired access tokens:

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpRequest,
  HttpHandler,
  HttpInterceptor,
  HttpHeaders,
} from '@angular/common/http';
import { Observable, EMPTY, throwError } from 'rxjs';
import { catchError, switchMap, take } from 'rxjs/operators';
import { Router } from '@angular/router';
import { AuthService } from '../services';

@Injectable()
export class UnauthorizedInterceptor implements HttpInterceptor {
  constructor(
    private router: Router,
    private readonly authService: AuthService
  ) {}

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
      catchError((error, caught) => {
        if (error.status === 401) {
          const newToken = this.authService.getNewToken();
          const updatedReq = req.clone({
            setHeaders: {
              Authorization: `Bearer ${newToken}`,
            },
          });
          return next.handle(updatedReq);
        }
        return EMPTY;
      })
    );
  }
}

This implementation is working as intended. However, the method getNewToken is asynchronous and when I update the code to

 intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
      catchError(async (error, caught) => {
        if (error.status === 401) {
          const newToken = await this.authService.getNewToken();
          const updatedReq = req.clone({
            setHeaders: {
              Authorization: `Bearer ${newToken}`,
            },
          });
          return next.handle(updatedReq);
        }
        return EMPTY;
      })
    );
  }

I am faced with the challenge of handling asynchronous operations within the catchError function. What could be a suitable solution for this scenario?

P.S: The getNewToken method can potentially be modified to return an observable instead of a promise, but I have not yet found a viable way to achieve this.

Update

The TypeScript error message states:

Type 'Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any> | Observable<...>>' is not assignable to type 'Observable<HttpEvent<any>>'.
  Type 'HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any> | Observable<...>' is not assignable to type 'HttpEvent<any>'.
    Type 'Observable<HttpEvent<any>>' is not assignable to type 'HttpEvent<any>'.ts(2322)

When using @ts-ignore, the browser throws the following error:

 EmptyError: no elements in sequence

Answer №1

Here is a suggested approach:

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error.status === 401) {
          return this.handleUnauthorized(request, next);
        } else {
          return throwError(error);
        }
      })
    );
  }

Below is the implementation of the "handleUnauthorized" method:


  handleUnauthorized(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
    // Implementation code here
  }

Make sure to include the following functionality inside authService:

  tokenSubject = new Subject<any>();
  .
  .
  .
  setToken(newToken: any) {
    this.tokenSubject.next(newToken)
  }

  getToken() {
    return this.tokenSubject.asObservable();
  }

Feel free to reach out with any questions in the comments!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why does TypeScript assign parameters in the opposite direction when assigning callbacks?

When a function is called with an argument, the argument type is matched to the parameter type. This means that the argument type must be the same as, or more specific than, the parameter type. For example: const foo = (bar: string | number) => { con ...

What are the steps to integrate webpack with .NET 6?

Struggling to incorporate webpack into .NET 6 razor pages. The existing documentation online only adds to my confusion. Here is a snippet from my file1.ts: export function CCC(): string { return "AAAAAA"; } And here is another snippet from ...

An issue occurred while creating a generic MessageBus in Typescript with rxjs due to a typing mismatch

I'm currently working on developing a versatile MessageBus in Typescript. My goal is to create message classes that inherit from a main MessageBusMessage class, allowing for subscription to messages of a specific class type with strong generic typing ...

Seeking out a particular key within a JSON object and then finding a match based on the id within that key's array - how can it be

Recently, I've been exploring JavaScript and encountering challenges when trying to apply array methods on objects. For instance, I received a fetch response and my goal is to extract the 'entries' key and then utilize the native Array.find( ...

What is the best way to export Class methods as independent functions in TypeScript that can be dynamically assigned?

As I work on rewriting an old NPM module into TypeScript, I encountered an intriguing challenge. The existing module is structured like this - 1.1 my-module.js export function init(options) { //initialize module } export function doStuff(params) { ...

Exploring Angular's capabilities with HttpClient and incorporating multiple parameters into a GET request

Using Angular6 for this project. The API I am working with is: https://localhost:44300/list/pete/id/open Within my Angular component, I have a method to call this API: getData(name, id, status): Observable<any[]> { // Setting up Params ...

Definition of PropTypes for content in a React navigation drawer

Currently, I am in the process of developing a custom drawer content using this specific guide: const DrawerContent = (props) => ( <DrawerContentScrollView {...props}> <AntDesign name="close" size={32} onPress={() => ...

How can I incorporate the LIKE operator in a query when dealing with PostgreSQL's String array type using TypeORM?

My database backend is PostgreSQL and I have a TypeORM object simplified as follows: @Entity() @Index(['name'], {unique: true}) export class Foo extends BaseEntity { @PrimaryGeneratedColumn('uuid') id: string; @Column() name: st ...

Tips for properly implementing an enum in TypeScript when using the React useState hook

What's the correct way to utilize my useState hook? I have this enum type: export enum Status { PENDING = 'pending', SUCCESS = 'success', ERROR = 'error', } And the useState hook: const [isValid, setIsValid] = use ...

extract the text content from an object

I am trying to add an object to the shopping cart. The item contains a key/value pair as shown in the following image: https://i.stack.imgur.com/5inwR.png Instead of adding the title with its innerText using p and style, I would like to find another ...

Utilize a selector within a component to transfer content using content projection in Angular version 12 and above

Could anyone advise on how to load a selector from one component and pass content into it from another component in Angular? I'm still learning Angular and would appreciate any guidance or concepts you can provide. Thank you! ...

Script for Excel Online utilizing data from a specific cell containing dates

I am currently working on a script in Excel online to automate date generation. My goal is to input a specific date into cell F1, such as 13/2/2023, and have G1 display the last day of the same year - 31/12/2023. The date needs to be extracted from cell A1 ...

Make sure to review the JSON file prior to loading the essential modules

Utilizing Angular to construct my Project. Planning to modify the API endpoint post Project construction. To achieve this, I have generated a JSON file in the assets directory, with all service files retrieving data from this file. The content in the JSON ...

Cannot access Injectable service in Angular2

In the angular2 application, there is a service named HttpClient. The purpose of this service is to include an authorization header in every request sent by the application to endpoints. import { Injectable } from '@angular/core'; import { He ...

The Angular Password Strength Extension will display an error message if the password strength is below 100

It's frustrating to keep trying different methods to achieve a simple task. I have a reactive form and all I want is to display an error if the password strength is not 100, indicating that it does not meet all the requirements. I can easily access t ...

The Angular Material Progress spinner and Progress bar fail to display

Currently focused on Angular 4, I initiated a fresh project using the following command : ng new test-app Afterwards, I executed : npm install --save @angular/material @angular/cdk ng g c first app.module.ts import { BrowserModule } from '@angular ...

Using Vuetify to filter items in a v-data-table upon clicking a button

My table structure is similar to this, https://i.sstatic.net/56TUi.png I am looking to implement a functionality where clicking on the Filter Button will filter out all items that are both male and valid with a value of true. users = [ { name: &apos ...

When the expectation of the result being null fails in a test, the test gets stuck in Angular 2 with Jasmine

I am facing an issue with a test that checks for the removal of a particular DOM element using ngIf. Whenever I use fixture.debugElement.query(By.css(".button-area")) to check the DOM, the result is either null or an actual DOM element. If the result is n ...

Issues arise with Typescript compiler on Windows systems due to soft symlinks causing compilation failures

In my TypeScript project, symlinks function properly on both macOS and Linux. However, when executing tsc in git-bash on Windows (not within WSL), the files cannot be resolved by tsc. ...

Ionic 4 does not support the command 'ionic package build ios development'

Struggling to make sense of the ionic 4 documentation, I attempt to build an iOS app on Windows using 'ionic package build ios'. Can this be done? Attempting to create an iOS app with ionic 4 using 'ionic package build ios'. ionic pac ...