Nest.js is failing to utilize the registered interceptor for dependency injection

Is there a special technique for successfully implementing `useValue` dependency injection in Nest.js interceptors? I have a dynamic module that looks similar to this:

@Module({})
export class SomeFeatureModule {
  static register({
    perRequestParams,
    ...clientOptions
  }: ModuleOptions): DynamicModule {
    const provider = new SomeClientProvider(clientOptions);
    return {
      module: SomeFeatureModule,
      providers: [
        {
          provide: SomeClientProvider,
          useValue: provider,
        },
        {
          provide: SomeInterceptor,
          useValue: new SomeInterceptor(provider, perRequestParams),
        },
      ],
      exports: [SomeClientProvider, SomeInterceptor],
    };
  }
}

...where the `SomeInterceptor` class is defined as follows:

@Injectable()
export class SomeInterceptor implements NestInterceptor {
  constructor(
    private readonly someClientProvider: SomeClientProvider,
    private readonly perRequestParams: (
      context: ExecutionContext,
    ) => EvaluationCriteria | Promise<EvaluationCriteria>,
  ) {}

  async intercept(
    execContext: ExecutionContext,
    next: CallHandler<any>,
  ): Promise<Observable<any>> {
    const params = await this.perRequestParams(execContext);
    return this.someClientProvider.injectLocalStorageData(params, () => next.handle());
  }
}

...but when I attempt to utilize the interceptor on my app's controller using:

@UseInterceptors(SomeInterceptor)

...I encounter the error:

Error: Nest can't resolve dependencies of the SomeInterceptor (SomeClientProvider, ?). Please ensure that the argument Function at index [1] is available in the AppModule context.

I am specifically importing `SomeFeatureModule.register(...)` within my `AppModule`:

@Module({})
export class AppModule {
  static register(env: Environment): DynamicModule {
    // ...
    return {
      module: AppModule,
      imports: [
        SomeFeatureModule.register({
          ...clientConfig,
          async perRequestParams(ctx) {
            // ...
          },
        }),
      ],
      // ...
    };
  }
}

Why is the dependency injection system attempting to resolve the constructor parameters for `SomeInterceptor` even though I'm already manually providing one?

Note that removing `@Injectable()` eliminates the startup error, but then the interceptor's constructor is invoked without any arguments, resulting in an issue.

Answer №1

When you use

@UseInterceptors(SomeInterceptor)
, NestJS's DI container is responsible for creating the instance of SomeInterceptor. It will not utilize the provider specified in useValue that you have defined. This behavior is not a built-in feature of the framework, which explains why using
@UseInterceptors('my_provider_token')
is also not supported.

I'm uncertain about any workarounds for this limitation.

Answer №2

After encountering an issue with the registered SomeInterceptor being ignored, I came up with a solution. Instead of relying on the interceptor, I created a new Symbol that users must register a value for:

export const PER_REQUEST_PARAMS = Symbol('PER_REQUEST_PARAMS');

The updated SomeInterceptor now looks like this:

@Injectable()
export class SomeInterceptor implements NestInterceptor {
  constructor(
    private readonly clientProvider: SomeClientProvider,
    @Inject(PER_REQUEST_PARAMS)
    private readonly perRequestParams: (
      context: ExecutionContext,
    ) => EvaluationCriteria | Promise<EvaluationCriteria>,
  ) {}

  // ...
}

Furthermore, the AppModule needs to make the following adjustments:

@Module({})
export class AppModule {
  static register(env: Environment): DynamicModule {
    // ...
    return {
      module: AppModule,
      imports: [
        SomeFeatureModule.register(clientConfig),
        // ...
      ],
      providers: [
        // ...
        {
          provide: PER_REQUEST_PARAMS,
          useValue: (ctx: ExecutionContext) => {
            // ...
          }
        }
      ]
      // ...
    };
  }
}

Interestingly, providing PER_REQUEST_PARAMS from within

SomeFeatureModule</code doesn't seem to work; it has to be done in <code>AppModule</code for proper resolution. This behavior appears to be counterintuitive and hopefully will be resolved as a bug.</p>
<p><strong>Update</strong>:</p>
<p>Upon further investigation, I discovered that registering a value for <code>PER_REQUEST_PARAMS
within
SomeFeatureModule</code does work. However, it is crucial to also export <code>PER_REQUEST_PARAMS
to ensure visibility when instantiating an instance of SomeInterceptor.

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

Bundle multiple internal modules in typescript for easy exporting

Currently, I am exploring the idea of implementing TypeScript in node.js. I have been accustomed to using TypeScript with the ///<reference.../> syntax for internal modules. However, as projects grow larger, managing interlinking references between m ...

Steps for connecting an HTML file to tabs in Angular 2

Currently, I have set up files like 'auth.ts' and 'auth.html', along with a main page (menu.html and menu.ts) where tabs are displayed. My intention is to associate the auth.html file with one of the tabs for user login functionality, a ...

Guide on: Reloading an AngularJS Route

I'm in the process of setting up a Typescript SPA project using Visual Studio and AngularJS for routing. Here is my current configuration... var app = angular.module("myApp", ["ngRoute"]); app.config(($routeProvider, $locationProvider) => { $route ...

Issues with Imported Routes Not Functioning as Expected

I am currently working on implementing routing in my Angular 2 project. All the components are functioning properly, but I encounter an error when I include 'appRoutes' in the imports section of app.module.ts. An unexpected TypeError occurs: C ...

Developing with Angular and Firebase: Setting up a new data node

Is there a way to create a new node called terriangen, add a key, and set the object data in Firebase? -usernames -{UID} -mylibrary -{key} -terriangen -{key} type:mountain name:1.png This is the ...

How can JSX be transformed into a React component?

Let's say there is a component named 'MyComponent', and I am trying to assign it to a variable of type 'MyComponent' in TypeScript using JSX element initialization, like this: let comp: MyComponent = <MyComponent somePropInit={ ...

Strategies for mitigating the use of Observables when passing data between Angular routes

When trying to exchange data between routes, the most effective method appears to be using a service. To ensure that data is updated and re-rendered in the view, we are required to utilize BehaviorSubject. Based on my understanding, a simple component wou ...

Angular Error: Potential security risk detected in resource URL context due to unsafe value being used

Hey there, I'm looking to display a dynamic pdf file. Initially, I encountered a CORS error, but managed to resolve it by using DOM Sanitizer. However, now I'm facing an issue with unsafe URLs. Any assistance would be greatly appreciated. Below ...

Troubleshooting: Resolving the error message 'Unable to assign to Partial<this>' within a subclass method

If I call the base class's update method using a subclass instance, it functions as expected. However, I encounter an error when attempting to do so within a subclass method: Argument of type '{ prop: number; }' is not compatible with par ...

We are unable to update the document in AngularFire as the document reference ID could not be retrieved

I am currently working on an update function that is designed to retrieve a specific document based on its unique document uid, which is connected to the authenticated user's uid. In another part of my code, I have a function that successfully fetche ...

Attention Needed - Certain vulnerabilities necessitate manual review for resolution

npm audit === Security Report from npm audit === # You have 1 vulnerability that can be resolved by running `npm update terser-webpack-plugin --depth 3` Severity Issue ...

How can I convert a property to an interface in Typescript?

I'm having trouble casting geometryType as I keep getting this error : IShape is a Type not a Namespace when attempting to do the following: interface IShape { readonly geometryType: "RECTANGLE" | "SQUARE" } let geom ...

The data in the filtered table is failing to revert back to its original state upon removing the filtered item from the webpage

I am currently working with an ng-multiselect dropdown to fetch data from a database. These dropdowns are being used to filter a data table on a webpage. However, I am facing an issue where when a dropdown item is selected, it correctly filters the table, ...

How can Multer library be effectively utilized to manage exceptions in NestJS controllers?

While working on creating a service to upload specific files from a Post multipart/form-data request, I came across an easy way to validate the fields count and name sent using the FileInterceptor decorator from @nestjs/platform-express. However, I'm ...

Typescript question: What is the specific error type associated with the 'throw' function in express-validator?

I am trying to identify the type of error thrown by this function: validationResult(req).throw() This is how the throw function is defined: throw() { if (!this.isEmpty()) { throw Object.assign(new Error(), utils_1.bindAll(this)); } } Here ...

React with Typescript - cannot be expressed as a function

I am currently exploring ReactJS and Typescript. While trying to authenticate a user using the methods below, I encountered the following error message: Unhandled Rejection (TypeError): auth.authenticate is not a function onSubmit src/components/Login/ind ...

Managing a click event with an element in React using TypeScript

Hey there, I'm pretty new to TypeScript and React. I have this event where I need to identify the element that triggered it so I can move another element close to it on the page. However, I'm facing some challenges trying to make it work in React ...

The imported variables are of a union type

In my nextjs project, I developed a customized hook to determine if a specific container is within the viewport using the intersection observer. Here's the code for the custom hook: import { useEffect, useRef, useState } from 'react'; cons ...

My React JS page suddenly turned blank right after I implemented a setState() function within my functional component

I was working on my code and everything seemed fine until I tried to incorporate the setState function with setcategory and setvalue. However, after making this change, my react page suddenly went blank. Can anyone help me identify what went wrong and pr ...

An issue arises in Typescript when attempting to pass an extra prop through the server action function in the useForm

I am struggling with integrating Next.js server actions with useFormState (to display input errors on the client side) and Typescript. As per their official documentation here, they recommend adding a new prop to the server action function like this: expo ...