NestJS - 如何向控制器添加动态路由?

dux*_*ard 6 node.js typescript nestjs

我有以下问题。假设我有一组静态资源的路由和路径,例如

const routes = [{ url: '/', path: 'assets/www' }]
Run Code Online (Sandbox Code Playgroud)

我想做的是创建一组动态路由来服务静态资源。在快速应用程序中,我会这样做:

const router = express.Router();    
routes.forEach(route => {
   router.use(route.url, express.static(path.join(__dirname, route.path)))
})
Run Code Online (Sandbox Code Playgroud)

但是可以在 NestJS 控制器中创建这样的逻辑吗?

@Controller()
export class ItemsController {
  constructor() {}

  @Get()
  findAll() {}

  @Get(':id')
  findOne() {}

  ....
}
Run Code Online (Sandbox Code Playgroud)

据我所知,所有 HTTP 请求处理程序都应该使用相应的装饰器进行预定义。

Rob*_*per 6

我会选择一种创建完全动态控制器的方法。Nest 本身不支持这一点,但您实际上可以使用 mixin 方法创建动态控制器和动态服务(这实际上很常见),另请参阅GitHub上的这个答案:

import { Post, Get, Controller } from '@nestjs/common';

interface Options {
  basePath: string
  entityName: string // you could even pass down DTO classes here, for maximum flexibility.
  providerName: string
}

// this service is generated dynamically as well
// preferably use a custom providerName.
interface DynamicService {
  foo: () => void
  bar: () => void
}

export const createDynamicController = (controllerOptions: Options) => {

  @Controller(controllerOptions.basePath)
  class MyController {

    constructor(
      @Inject(options.providerName) myProvider: DynamicProvider
    ){}

    @Get(options.entityName)
    findOne(){
      return this.myProvider.foo()
    }

    @Post(options.entityName)
    create(){
      return this.myProvider.foo()
    }

  }

  
  return MyController
}
Run Code Online (Sandbox Code Playgroud)

使用这种方法,理论上您可以动态创建所有控制器,但它要求更多地了解 NestJS 依赖树。

您现在可以创建控制器,如下所示:

{
   controllers: [createDynamicController({
     basePath: 'foo',
     entityName: 'barz',
     providerName: 'custom-provider-name'
    })
   ]
}

Run Code Online (Sandbox Code Playgroud)


jos*_*fer 0

你可以做的是有一个动态控制器 -> 带有参数标识符 -> 就好像它就像一个事件处理程序 ID...(实际上不仅仅是使用它作为思考过程的一种方式。)

然后在您连接的服务中 -> 您可以进行 5 个增删改查操作,但是在您的服务中您注入静态资源 -> 并使用该标识符来路由调用。

query dto

export class QueryDto {
  readonly params?: any[];
  readonly body: any;
}
Run Code Online (Sandbox Code Playgroud)
controller

 @Post(':serviceId')
  async create(@Param('serviceId') serviceId: string, @Body() queryDto: QueryDto) {
    return await this.rootService.create(serviceId, queryDto);
  }
Run Code Online (Sandbox Code Playgroud)
inside your root service
 // childService = used to route the request dynamically ->
 // body = your body or if you dont need a body this is where any parameters would go. which is why it's any (for if it was a get)
 // params last => incase your doing a put or something where you need a body and parameters -> but it also allows it to be optional.

 async create(childService: string, data: any, params: any[]): Promise<any> {
    if (!id) {
      return await this[childService].create(data.body, ...data.params).exec() 
    }
Run Code Online (Sandbox Code Playgroud)

只是一个想法,但如果一切都是静态的,那么这应该适合你。只需使用根服务作为直通即可。从单个控制器 -> 到各种服务。