简体   繁体   English

有条件地将服务类实例化为 NestJS 中的提供者

[英]Conditionally instantiate service class as a provider in NestJS

I have a controller called User and two service classes: UserAdminService and UserSuperAdminService .我有一个名为User的控制器和两个服务类: UserAdminServiceUserSuperAdminService When a user makes a request to any endpoint of the User controller, I want to check if the user making the request is an Admin or a Super Admin (based on the roles in the token) and instantiate the correct service ( UserAdminService or UserSuperAdminService ).当用户向User控制器的任何端点发出请求时,我想检查发出请求的用户是管理员还是超级管理员(基于令牌中的角色)并实例化正确的服务( UserAdminServiceUserSuperAdminService ) . Note that the two services implement the same UserService interface (just the internals of the methods that change a bit).请注意,这两个服务实现了相同的UserService接口(只是方法的内部结构稍有变化)。 How can I make this with NestJS?我怎样才能用 NestJS 做到这一点?

What I tried:我尝试了什么:

user.module.ts用户.module.ts

providers: [
    {
      provide: "UserService",
      inject: [REQUEST],
      useFactory: (request: Request) => UserServiceFactory(request)
    }
  ],

user-service.factory.ts用户服务.factory.ts

export function UserServiceFactory(request: Request) {

    const { realm_access } = JwtService.parseJwt(
        request.headers["authorization"].split(' ')[1]
    );
    if (realm_access["roles"].includes(RolesEnum.SuperAdmin))
        return UserSuperAdminService;
    else
        return UserAdminService;
}

user.controller.ts用户.controller.ts

  constructor(
      @Inject("UserService") private readonly userService: UserServiceInterface
  ) {}

One of the reasons my code is not working is because I am returning the classes and not the instantiated objects from the factory, but I want NestJS to resolve the services dependencies.我的代码不工作的原因之一是因为我返回的是类而不是工厂中的实例化对象,但我希望 NestJS 解决服务依赖关系。 Any ideas?有任何想法吗?

Rather than passing back the class to instantiate, which Nest doesn't handle, you could add the UserSuperAdminService and UserAdminService to the inject array, and pass back the instance that Nest then would create per request.您可以将UserSuperAdminServiceUserAdminService添加到inject数组,然后传回 Nest 然后根据请求创建的实例,而不是传回要实例化的类,Nest 不处理该类。

providers: [
    {
      provide: "UserService",
      inject: [REQUEST, UserSuperAdminService, UserAdminService],
      useFactory: (request: Request, superAdminService: UserSuperAdminService, adminService: UserAdminService) => UserServiceFactory(request, superAdminService, adminService)
    }
...
]

export function UserServiceFactory(request: Request, superAdminService: UserSuperAdminService, adminService: UserAdminService) {

    const { realm_access } = JwtService.parseJwt(
        request.headers["authorization"].split(' ')[1]
    );
    if (realm_access["roles"].includes(RolesEnum.SuperAdmin))
        return superAdminService;
    else
        return adminService;
}

Instead of trying to conditionally instantiate a service class you could create a global middleware to redirect the request to the appropriate controller eg您可以创建一个全局中间件来将请求重定向到适当的控制器,而不是尝试有条件地实例化服务类,例如

 import { Injectable, NestMiddleware } from '@nestjs/common'; @Injectable() export class AdminUserMiddleware implements NestMiddleware { use(req: any, res: any, next: () => void) { const { realm_access } = JwtService.parseJwt( req.headers["authorization"].split(' ')[1] ); if (realm_access["roles"].includes(RolesEnum.SuperAdmin)) { req.url = req.url.replace(/^\/, '/super-admin/'); } next(); } }

Then you can apply it to all routes in your app.module.ts然后你可以将它应用到你的 app.module.ts 中的所有路由

 @Module({ imports: [HttpModule], controllers: [UserAdminController, UserSuperAdminController] providers: [UserSuperAdminService, UserAdminService] }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(AdminUserMiddleware).forRoutes('/'); } }

and have the following controlers:并具有以下控制器:

 @Controller('/') export class UserAdminController { private readonly logger: Logger = new Logger(UserAdminController.name); constructor(private readonly userAdminService: UserAdminService) {}

 @Controller('/super-admin') export class UserSuperAdminController { private readonly logger: Logger = new Logger(UserSuperAdminController.name); constructor(private readonly userSuperAdminService: UserSuperAdminService) {} }

See the NestJS docs and this post for further details有关详细信息,请参阅 NestJS文档和这篇文章

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM