nestjs icon indicating copy to clipboard operation
nestjs copied to clipboard

Using the "modules" package to create configurable middleware

Open JJHDoubleD opened this issue 3 years ago • 1 comments

@golevelup/nestjs-modules works great to create dynamically configurable services. But is there any way to create dynamically configurable middleware? I've tried using the exact same method used for services, but it can't inject the dependencies.

The middleware:

@Injectable()
export class AuthMiddleware implements NestMiddleware {
  constructor(@Inject(USER_SERVICE) private readonly userService: UserService) {
    console.log('userService findAll: ', userService.findAll());
  }

  use(req: any, res: any, next: () => void) {
    console.log('AuthMiddleware called!');

    next();
  }
}

The module containing the middleware:

@Module({
  providers: [AuthService, AuthMiddleware],
  imports: [ExtModule],
})
export class AuthModule extends createConfigurableDynamicRootModule<
  AuthModule,
  AuthModuleOptions
>(AUTH_OPTIONS, {
  providers: [
    {
      provide: AUTH_SECRET,
      inject: [AUTH_OPTIONS],
      useFactory: (options: AuthModuleOptions) => options.secret,
    },
    {
      provide: USER_SERVICE,
      inject: [AUTH_OPTIONS],
      useFactory: (options: AuthModuleOptions) => options.userService,
    },
  ],
  controllers: [AuthController],
}) {}

Importing the module and trying to use the middleware:

@Module({
  imports: [
    ConfigModule.forRoot(),
    AuthModule.forRootAsync(AuthModule, {
      imports: [ConfigModule, UserModule],
      inject: [ConfigService, UserService],
      useFactory: (config: ConfigService, userService: UserService) => {
        return {
          secret: config.get('AUTH_SECRET_VALUE'),
          userService,
        };
      },
    }) as DynamicModule,
    UserModule,
  ],
  controllers: [UserController],
  providers: [],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(AuthMiddleware).forRoutes('*');
  }
}

Now when initializing the AuthModule dependencies the middleware class is clearly instantiated correctly, the userService.findAll being logged:

userService findAll:  []

But the problem is that when then actually using the middleware in configure(), the injected context is not used

...\app\node_modules\@nestjs\core\injector\injector.js:193
            throw new unknown_dependencies_exception_1.UnknownDependenciesException(wrapper.name, dependencyContext, moduleRef);
                  ^
Error: Nest can't resolve dependencies of the class AuthMiddleware {
    constructor(userService) {
        this.userService = userService;
        console.log('userService findAll: ', userService.findAll());
    }
    use(req, res, next) {
        console.log('AuthMiddleware called!');
        next();
    }
} (?). Please make sure that the argument Symbol(USER_SERVICE) at index [0] is available in the AppModule context.

JJHDoubleD avatar Jul 25 '22 02:07 JJHDoubleD

@JJHDoubleD This might help you (https://github.com/jmcdo29/nest-dynamic-module-middleware)

underfisk avatar Jul 28 '22 11:07 underfisk