Papooch / nestjs-cls

A continuation-local storage (async context) module compatible with NestJS's dependency injection.
https://papooch.github.io/nestjs-cls/
MIT License
390 stars 23 forks source link

Can't resolve proxy provider #66

Closed mydnicq closed 1 year ago

mydnicq commented 1 year ago

I have trouble to get proxy provider working in my case:

// app.module.ts
@InjectableProxy()
export class MyAsyncCtx {
  beforeRender: any[];
}

@Module({
  imports: [
    ClsModule.forRoot({
      global: true,
      interceptor: {
        mount: true,
      },
      proxyProviders: [MyAsyncCtx],
    }),
  ],
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: ResponseInterceptor,
    },
  ],
})
export class AppModule {}

// response.interceptor.ts
@Injectable()
export class ResponseInterceptor<T>
  implements NestInterceptor
{
  constructor(
    private readonly myAsyncCtx: MyAsyncCtx,
  ) {}

  ...

NestJS DI throws error:

Nest can't resolve dependencies of the ResponseInterceptor (?). Please make sure that the argument dependency at index [0] is available in the AppModule context.

Potential solutions:
- If dependency is a provider, is it part of the current AppModule?
- If dependency is exported from a separate @Module, is that module imported within AppModule?
  @Module({
    imports: [ /* the Module containing dependency */ ]
  })

Per my understanding everything should be configured correctly. I've also took a look in nestjs-cls source code and cofirmed that proxyProviders: [MyAsyncCtx] are indeed exported from ClsModule. Now I don't have any ideas more why this still doesn't work?

Papooch commented 1 year ago

Good question, this should indeed work. Let me dig into that.

Papooch commented 1 year ago

I discovered this was not covered by tests, so I added them and they pass.

This does not seem like a bug with the library, could you share a minimal working reproduction of the issue?

Please make sure you're on the latest version of the library (v3.1.1 a the time of writing).

mydnicq commented 1 year ago

@Papooch Thank you for a quick reply. However, I'm still experiencing the same issue. I prepared a repo where you can check what is happening.

https://github.com/tadejstanic/nestjs-cls-debug

Papooch commented 1 year ago

Found the error - you have a circular dependency between the files app.module and response.interceptor.ts (they both import stuff from one another). You can easily break the cycle by putting the AsyncCtx class into a separate file. When I did that, the app bootstrapped successfully.

This is also hinted in the error message:

Nest can't resolve dependencies of the ResponseInterceptor (?). Please make sure that the argument dependency at index [0] is available in the AppModule context

I don't know why I missed that before, but if the error says "dependency" instead of the actual name of the class (in this case "AsyncCtx"), it usually means that there is some import cycle and the name is not known to the runtime.

mydnicq commented 1 year ago

@Papooch Thank you :) I was blindly following the docs from your package not realizing that I'm actually having a circular dependency. In a real app, that AsyncCtx would be definitely in a separate file. Sorry for this stupid mistake that took you precious time.