如何在控制器方法(例如NestJs)中具有多个修饰的参数?

时间:2020-06-06 10:52:11

标签: javascript node.js typescript architecture nestjs

我对NestJs如何成功创建其控制器非常感兴趣。例如,我可以在NestJs控制器中执行此操作。

@Controller('/mycontroller')
class MyController {

    @Post()
    createItemRoute(
      @Query() myQuery: myQueryDto,
      @Body() body: bodyDto,
      @Res() res: Response
      // I can add more parameters to here if I want or have a different set of parameters in another method
    ) {
      console.log('Query:', myQuery)
      console.log('Body:', body)
      console.log('Response:', res)
    }
}

我基本上可以在createItemRoute中添加任意数量的参数。对参数进行修饰,并使用修饰后的参数很好地处理了参数中的最终值,供我使用。

由于NestJs使用Express,因此我假设createItemRoute是通过标准Express reqresnext参数传递的,然后进一步传递给修饰的处理参数。

我很好奇这是如何完成的,因此决定尝试在练习中复制相同的效果,但是我不知道该如何实现。这是我到目前为止的内容:

function Post() {
    return function (target: Record<string, any>, key: string, descriptor: PropertyDescriptor) {
        const original: Function = descriptor.value;

        // 1. To get the arguments of the original method
        const originalArguments = descriptor.value.arguments;  // But this causes an error that arguments cannot be used

        // 2. Changes the original method's signature to receive from Express just as an ordinary middleware function
        descriptor.value = function(req: Request, res: Response) { 
          const newArguments = []
          // 3. To loop through the arguments retrieved and apply them
          for (const param in originalArguments) {  // This fails too because I couldn't retrieve the arguments into originalArguments in the previous line
            newArguments.push(param(req, res))  // Somehow passes the req and res into the decorated arguments of the original method for them to process and return their processed values
          }
          originalMethod.apply(this, newArguments). // Then apply with the new arguments
        }
        return descriptor;
    }
}

// 5. The @Body() decorator which returns a function so that it can be used in the Post() decorator
function Body() {
  return function (target: Record<string, any>, key: string, descriptor: PropertyDescriptor) {
    return (req, res) => {
      return res.body
    }
  }
}

const testMyController = new MyController();
const mockReq = { body: 'my body content' }
const mockRes = { status: (code) => true }
// 4. Assuming Express will pass its req and res into the function
testMyController.createItemRoute(mockReq, mockRes)  // This will cause Typescript to throw an error that the method signature mismatches the one created in MyController

在我尝试过的过程中,想法是通过装饰器将createItemRoute中的MyController包装在另一个函数中,该装饰器可用于从Express接收参数。但是,我在示例代码中将它们标记为几个问题。

  1. 由于我可以在控制器方法(createItemRoute)中添加任意数量的参数,因此需要一种方法来检索数组中的参数。该方法未使用...args声明,因此我不能直接获取它们。使用descriptor.value.arguments还会引发不允许的错误。我希望能一直保持严格的状态。

  2. 我将原始方法的签名转换为适合典型Express中间件的形状,以便以后可以将其作为中间件传递给Express。这不起作用,我们将在后面的步骤4中看到。

  3. 由于有多个装饰参数传递到createItemRoute中,因此我需要遍历它们,并为它们提供Express中的原始reqres,以便装饰器可以处理它们并返回它们的值。但是,这里有几个问题。

    • 首先,循环失败,因为首先我无法从原始方法中检索参数。
    • 第二,我不确定如何将reqres传递给装饰器。我拥有param(req, res)的那部分似乎也不起作用。
  4. 因此,由于我已经通过装饰器转换了createItemRoute的方法签名,所以我认为我可以开始从Express接收req和res值了。我嘲笑了reqres,并试图将它们传递到createItemRoute方法中。但是,由于我使用的是Typescript,它将开始抱怨并引发有关方法签名不匹配的错误!

  5. @Body装饰器中,我计划在步骤#3中以某种方式从@Post装饰器接收请求和资源。但这显然似乎行不通。

我需要帮助来阐明如何实现控制器在NestJs中的工作方式。

0 个答案:

没有答案