Typescript 直接在控制器函数中验证枚举

Typescript 直接在控制器函数中验证枚举,typescript,rest,nestjs,Typescript,Rest,Nestjs,我在RESTAPI中有一个查询参数,该参数的值应该受到枚举类型的限制。我正在寻找一种方法,当客户机给出不同的内容时,抛出一个“错误请求”错误 我的枚举如下所示: export enum Precision { S = 's', MS = 'ms', U = 'u', NS = 'ns', } @Get(':deviceId/:datapoint/last') @ApiOkResponse() @ApiQuery({name: 'precision',

我在RESTAPI中有一个查询参数,该参数的值应该受到枚举类型的限制。我正在寻找一种方法,当客户机给出不同的内容时,抛出一个“错误请求”错误

我的枚举如下所示:

export enum Precision {
    S = 's',
    MS = 'ms',
    U = 'u',
    NS = 'ns',
}
  @Get(':deviceId/:datapoint/last')
  @ApiOkResponse()
  @ApiQuery({name: 'precision', enum: Precision})
  getLastMeasurement(
    @Param('deviceId') deviceId: string,
    @Param('datapoint') datapoint: string,
    @Query('precision') precision: Precision = Precision.S,
    @Res() response: Response,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }
getLastMeasurement(
  ... // some other params
    @Query('precision', new DefaultValuePipe(Precision.S)) precision: Precision
  ) { 
  ... // do something
}
我的控制器功能如下所示:

export enum Precision {
    S = 's',
    MS = 'ms',
    U = 'u',
    NS = 'ns',
}
  @Get(':deviceId/:datapoint/last')
  @ApiOkResponse()
  @ApiQuery({name: 'precision', enum: Precision})
  getLastMeasurement(
    @Param('deviceId') deviceId: string,
    @Param('datapoint') datapoint: string,
    @Query('precision') precision: Precision = Precision.S,
    @Res() response: Response,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }
getLastMeasurement(
  ... // some other params
    @Query('precision', new DefaultValuePipe(Precision.S)) precision: Precision
  ) { 
  ... // do something
}
我这里的问题是,该函数也接受其他值(例如,我可以发送一个f作为查询参数的值)。该函数不会向客户端返回错误,但我希望在每个控制器函数的开头不写if-else块的情况下返回错误。
我想有一个相当简单的解决方案,但当我尝试在internet上查找时,我总是会在DTO中得到类验证的结果,而不是直接在查询参数/REST控制器中进行简单的枚举验证

谢谢您抽出时间,

J

您应该能够创建一个类,如
LastMeasurementQueryParams
,该类使用decorators,并使用检查并确保发送了一个预期值

该类可以如下所示:

export enum Precision {
    S = 's',
    MS = 'ms',
    U = 'u',
    NS = 'ns',
}
  @Get(':deviceId/:datapoint/last')
  @ApiOkResponse()
  @ApiQuery({name: 'precision', enum: Precision})
  getLastMeasurement(
    @Param('deviceId') deviceId: string,
    @Param('datapoint') datapoint: string,
    @Query('precision') precision: Precision = Precision.S,
    @Res() response: Response,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }
getLastMeasurement(
  ... // some other params
    @Query('precision', new DefaultValuePipe(Precision.S)) precision: Precision
  ) { 
  ... // do something
}
导出类LastMeasurementQueryParams{
@IsEnum(精度)
精度:精度;
}
然后您的控制器可以如下所示:

export enum Precision {
    S = 's',
    MS = 'ms',
    U = 'u',
    NS = 'ns',
}
  @Get(':deviceId/:datapoint/last')
  @ApiOkResponse()
  @ApiQuery({name: 'precision', enum: Precision})
  getLastMeasurement(
    @Param('deviceId') deviceId: string,
    @Param('datapoint') datapoint: string,
    @Query('precision') precision: Precision = Precision.S,
    @Res() response: Response,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }
getLastMeasurement(
  ... // some other params
    @Query('precision', new DefaultValuePipe(Precision.S)) precision: Precision
  ) { 
  ... // do something
}
@Get(':deviceId/:datapoint/last')
@ApiOkResponse()
@ApiQuery({name:'precision',enum:precision})
getLastMeasurement(
@Param('deviceId')deviceId:string,
@参数('datapoint')数据点:字符串,
@查询('precision')精度:LastMeasurementQueryParams={precision:precision.S},
@Res()response:response,
) {
控制台日志(精度);
....
response.status(HttpStatus.OK).send(body);
}

您应该能够创建一个类似于
LastMeasurementQueryParams
的类,该类使用decorators,并使用检查并确保发送了一个预期值

该类可以如下所示:

export enum Precision {
    S = 's',
    MS = 'ms',
    U = 'u',
    NS = 'ns',
}
  @Get(':deviceId/:datapoint/last')
  @ApiOkResponse()
  @ApiQuery({name: 'precision', enum: Precision})
  getLastMeasurement(
    @Param('deviceId') deviceId: string,
    @Param('datapoint') datapoint: string,
    @Query('precision') precision: Precision = Precision.S,
    @Res() response: Response,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }
getLastMeasurement(
  ... // some other params
    @Query('precision', new DefaultValuePipe(Precision.S)) precision: Precision
  ) { 
  ... // do something
}
导出类LastMeasurementQueryParams{
@IsEnum(精度)
精度:精度;
}
然后您的控制器可以如下所示:

export enum Precision {
    S = 's',
    MS = 'ms',
    U = 'u',
    NS = 'ns',
}
  @Get(':deviceId/:datapoint/last')
  @ApiOkResponse()
  @ApiQuery({name: 'precision', enum: Precision})
  getLastMeasurement(
    @Param('deviceId') deviceId: string,
    @Param('datapoint') datapoint: string,
    @Query('precision') precision: Precision = Precision.S,
    @Res() response: Response,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }
getLastMeasurement(
  ... // some other params
    @Query('precision', new DefaultValuePipe(Precision.S)) precision: Precision
  ) { 
  ... // do something
}
@Get(':deviceId/:datapoint/last')
@ApiOkResponse()
@ApiQuery({name:'precision',enum:precision})
getLastMeasurement(
@Param('deviceId')deviceId:string,
@参数('datapoint')数据点:字符串,
@查询('precision')精度:LastMeasurementQueryParams={precision:precision.S},
@Res()response:response,
) {
控制台日志(精度);
....
response.status(HttpStatus.OK).send(body);
}

这里有两个问题

第一个问题是,您以错误的方式传递了
precision
params的默认值。您必须像这样使用
DefaultValuePipe

export enum Precision {
    S = 's',
    MS = 'ms',
    U = 'u',
    NS = 'ns',
}
  @Get(':deviceId/:datapoint/last')
  @ApiOkResponse()
  @ApiQuery({name: 'precision', enum: Precision})
  getLastMeasurement(
    @Param('deviceId') deviceId: string,
    @Param('datapoint') datapoint: string,
    @Query('precision') precision: Precision = Precision.S,
    @Res() response: Response,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }
getLastMeasurement(
  ... // some other params
    @Query('precision', new DefaultValuePipe(Precision.S)) precision: Precision
  ) { 
  ... // do something
}
第二个是枚举验证。NestJS只有6种类型的validationPipes,并且没有一种验证枚举,因此您必须创建自己的自定义验证管道来验证枚举

有两种可能的方法可以做到这一点:

  • 创建自定义管道以仅验证特定枚举
  • 创建自定义管道泛型以验证任何枚举 基于此,它将类似于:

  • 仅验证特定的枚举
  • 验证任何枚举(我的最爱)

  • 这里有两个问题

    第一个问题是,您以错误的方式传递了
    precision
    params的默认值。您必须像这样使用
    DefaultValuePipe

    export enum Precision {
        S = 's',
        MS = 'ms',
        U = 'u',
        NS = 'ns',
    }
    
      @Get(':deviceId/:datapoint/last')
      @ApiOkResponse()
      @ApiQuery({name: 'precision', enum: Precision})
      getLastMeasurement(
        @Param('deviceId') deviceId: string,
        @Param('datapoint') datapoint: string,
        @Query('precision') precision: Precision = Precision.S,
        @Res() response: Response,
      ) {
        console.log(precision);
        ....
        response.status(HttpStatus.OK).send(body);
      }
    
    getLastMeasurement(
      ... // some other params
        @Query('precision', new DefaultValuePipe(Precision.S)) precision: Precision
      ) { 
      ... // do something
    }
    
    第二个是枚举验证。NestJS只有6种类型的validationPipes,并且没有一种验证枚举,因此您必须创建自己的自定义验证管道来验证枚举

    有两种可能的方法可以做到这一点:

  • 创建自定义管道以仅验证特定枚举
  • 创建自定义管道泛型以验证任何枚举 基于此,它将类似于:

  • 仅验证特定的枚举
  • 验证任何枚举(我的最爱)

  • 嗨,杰,谢谢你的回答。当我阅读您的方法时,我想知道框架如何知道如何将查询参数转换为必须创建的对象的成员?不管怎样,我测试了你的方法,但得到了一个错误:TypeError:无法读取Unfinedhi Jay的属性“constructor”,谢谢你的回答。当我阅读您的方法时,我想知道框架如何知道如何将查询参数转换为必须创建的对象的成员?无论如何,我测试了您的方法,但得到了一个错误:TypeError:无法读取未定义的属性“构造函数”