使用 NestJS 和 class-validator 创建一个 Header 自定义验证
Create a Header Custom Validation with NestJS and class-validator
我一直在努力使用 class-validator 和 NestJS 验证来验证请求,并尝试验证 header 内容。我的基本界面都可以使用,但现在我正在尝试以相同的方式比较一些 header 字段数据。
我有这个 来尝试处理 header,但是这个问题的解决方案 return 将是 header。我希望能够处理所有这些,类似于处理所有 body() 数据的方式。
我需要能够创建自定义装饰器来提取 header 字段,并能够将它们传递到 class-validator DTO。
对于实例,我想验证三个 header 字段,例如:
User-Agent = 'Our Client Apps'
Content-Type = 'application/json'
traceabilityId = uuid
还有更多字段,但如果我能做到这一点,那么我可以推断出其余部分。我有一个简单的控制器示例:
@Controller(/rest/package)
export class PackageController {
constructor(
private PackageData_:PackageService
)
{ }
...
@Post('inquiry')
@HttpCode(HttpStatus.OK) // Not creating data, but need body, so return 200 OK
async StatusInquiry(
@RequestHeader() HeaderInfo:HeadersDTO, // This should be the Headers validation using the decorator from the question above.
我正在尝试验证请求的 headers 是否包含一些特定数据,并且我正在使用 NestJS。我找到了这个 information。虽然这是我想要做的,而且看起来不错,但 ClassType 引用不存在,我不确定该用什么代替。
从例子中,装饰器是指。
request-header.decorator.ts
export interface iError {
statusCode:number;
messages:string[];
error:string;
}
export const RequestHeader = createParamDecorator(
async (value: any, ctx: ExecutionContext) => {
// extract headers
const headers = ctx.switchToHttp().getRequest().headers;
// Convert headers to DTO object
const dto = plainToClass(value, headers, { excludeExtraneousValues: true });
// Validate
const errors: ValidationError[] = await validate(dto);
if (errors.length > 0) {
let ErrorInfo:IError = {
statusCode: HttpStatus.BAD_REQUEST,
error: 'Bad Request',
message: new Array<string>()
};
errors.map(obj => {
AllErrors = Object.values(obj.constraints);
AllErrors.forEach( (OneError) => {
OneError.forEach( (Key) => {
ErrorInfo.message.push(Key);
});
});
// Your example, but wanted to return closer to how the body looks, for common error parsing
//Get the errors and push to custom array
// let validationErrors = errors.map(obj => Object.values(obj.constraints));
throw new HttpException(`${ErrorInfo}`, HttpStatus.BAD_REQUEST);
}
// return header dto object
return dto;
},
我在将约束一般映射到字符串数组时遇到问题。
我的HeadersDTO.ts:
import { Expose } from 'class-transformer';
import { Equals, IsIn, IsString } from 'class-validator';
export class HeadersDTO {
@IsString()
@Equals('OurApp')
@Expose({ name: 'user-agent' })
public readonly 'user-agent':string;
@IsString()
@IsIn(['PRODUCTION', 'TEST'])
public readonly operationMode:string;
}
Headers 正在通过 Postman 发送请求:
Content-Type:application/json
operationMode:PRODUCTION
Accept-Language:en
如 issue you referenced 中所述,您需要创建一个 DTO class 并将其传递给 RequestHeader
装饰器。
例如
export class MyHeaderDTO {
@IsString()
@IsDefined()
@Expose({ name: 'myheader1' }) // required as headers are case insensitive
myHeader1: string;
}
...
@Get('/hello')
getHello(@RequestHeader(MyHeaderDTO) headers: MyHeaderDTO) {
console.log(headers);
}
我刚刚测试了以下代码,它可以正常工作。我认为你在这里缺少合适的类型,
async StatusInquiry(
@RequestHeader() HeaderInfo:HeadersDTO,
你应该 HeadersDTO 作为参数传入 RequestHeader Decorator this @RequestHeader(HeadersDTO) HeaderInfo:HeadersDTO,
然后我就这样创建了customDecorator.ts,
export const RequestHeader = createParamDecorator(
//Removed ClassType<unknown>,, I don't think you need this here
async (value: any, ctx: ExecutionContext) => {
// extract headers
const headers = ctx.switchToHttp().getRequest().headers;
// Convert headers to DTO object
const dto = plainToClass(value, headers, { excludeExtraneousValues: true });
// Validate
const errors: ValidationError[] = await validate(dto);
if (errors.length > 0) {
//Get the errors and push to custom array
let validationErrors = errors.map(obj => Object.values(obj.constraints));
throw new HttpException(`Validation failed with following Errors: ${validationErrors}`, HttpStatus.BAD_REQUEST);
}
// return header dto object
return dto;
},
);
我的HeadersDTO.ts文件
export class HeadersDTO
{
@IsDefined()
@Expose({ name: 'custom-header' })
"custom-header": string; // note the param here is in double quotes
}
之所以我在查看编译后的TS文件时发现了这个,它看起来是这样的,
class HeadersDTO {
}
tslib_1.__decorate([
class_validator_1.IsDefined(),
class_transformer_1.Expose({ name: 'custom-header' }),
tslib_1.__metadata("design:type", String)
], HeadersDTO.prototype, "custom-header", void 0);
exports.HeadersDTO = HeadersDTO;
当我没有通过 header ,
时出现以下错误
[
ValidationError {
target: HeadersDTO { 'custom-header': undefined },
value: undefined,
property: 'custom-header',
children: [],
constraints: { isDefined: 'custom-header should not be null or undefined' }
}
]
我一直在努力使用 class-validator 和 NestJS 验证来验证请求,并尝试验证 header 内容。我的基本界面都可以使用,但现在我正在尝试以相同的方式比较一些 header 字段数据。
我有这个
我需要能够创建自定义装饰器来提取 header 字段,并能够将它们传递到 class-validator DTO。
对于实例,我想验证三个 header 字段,例如:
User-Agent = 'Our Client Apps'
Content-Type = 'application/json'
traceabilityId = uuid
还有更多字段,但如果我能做到这一点,那么我可以推断出其余部分。我有一个简单的控制器示例:
@Controller(/rest/package)
export class PackageController {
constructor(
private PackageData_:PackageService
)
{ }
...
@Post('inquiry')
@HttpCode(HttpStatus.OK) // Not creating data, but need body, so return 200 OK
async StatusInquiry(
@RequestHeader() HeaderInfo:HeadersDTO, // This should be the Headers validation using the decorator from the question above.
我正在尝试验证请求的 headers 是否包含一些特定数据,并且我正在使用 NestJS。我找到了这个 information。虽然这是我想要做的,而且看起来不错,但 ClassType 引用不存在,我不确定该用什么代替。
从例子中,装饰器是指。
request-header.decorator.ts
export interface iError {
statusCode:number;
messages:string[];
error:string;
}
export const RequestHeader = createParamDecorator(
async (value: any, ctx: ExecutionContext) => {
// extract headers
const headers = ctx.switchToHttp().getRequest().headers;
// Convert headers to DTO object
const dto = plainToClass(value, headers, { excludeExtraneousValues: true });
// Validate
const errors: ValidationError[] = await validate(dto);
if (errors.length > 0) {
let ErrorInfo:IError = {
statusCode: HttpStatus.BAD_REQUEST,
error: 'Bad Request',
message: new Array<string>()
};
errors.map(obj => {
AllErrors = Object.values(obj.constraints);
AllErrors.forEach( (OneError) => {
OneError.forEach( (Key) => {
ErrorInfo.message.push(Key);
});
});
// Your example, but wanted to return closer to how the body looks, for common error parsing
//Get the errors and push to custom array
// let validationErrors = errors.map(obj => Object.values(obj.constraints));
throw new HttpException(`${ErrorInfo}`, HttpStatus.BAD_REQUEST);
}
// return header dto object
return dto;
},
我在将约束一般映射到字符串数组时遇到问题。
我的HeadersDTO.ts:
import { Expose } from 'class-transformer';
import { Equals, IsIn, IsString } from 'class-validator';
export class HeadersDTO {
@IsString()
@Equals('OurApp')
@Expose({ name: 'user-agent' })
public readonly 'user-agent':string;
@IsString()
@IsIn(['PRODUCTION', 'TEST'])
public readonly operationMode:string;
}
Headers 正在通过 Postman 发送请求:
Content-Type:application/json
operationMode:PRODUCTION
Accept-Language:en
如 issue you referenced 中所述,您需要创建一个 DTO class 并将其传递给 RequestHeader
装饰器。
例如
export class MyHeaderDTO {
@IsString()
@IsDefined()
@Expose({ name: 'myheader1' }) // required as headers are case insensitive
myHeader1: string;
}
...
@Get('/hello')
getHello(@RequestHeader(MyHeaderDTO) headers: MyHeaderDTO) {
console.log(headers);
}
我刚刚测试了以下代码,它可以正常工作。我认为你在这里缺少合适的类型,
async StatusInquiry(
@RequestHeader() HeaderInfo:HeadersDTO,
你应该 HeadersDTO 作为参数传入 RequestHeader Decorator this @RequestHeader(HeadersDTO) HeaderInfo:HeadersDTO,
然后我就这样创建了customDecorator.ts,
export const RequestHeader = createParamDecorator(
//Removed ClassType<unknown>,, I don't think you need this here
async (value: any, ctx: ExecutionContext) => {
// extract headers
const headers = ctx.switchToHttp().getRequest().headers;
// Convert headers to DTO object
const dto = plainToClass(value, headers, { excludeExtraneousValues: true });
// Validate
const errors: ValidationError[] = await validate(dto);
if (errors.length > 0) {
//Get the errors and push to custom array
let validationErrors = errors.map(obj => Object.values(obj.constraints));
throw new HttpException(`Validation failed with following Errors: ${validationErrors}`, HttpStatus.BAD_REQUEST);
}
// return header dto object
return dto;
},
);
我的HeadersDTO.ts文件
export class HeadersDTO
{
@IsDefined()
@Expose({ name: 'custom-header' })
"custom-header": string; // note the param here is in double quotes
}
之所以我在查看编译后的TS文件时发现了这个,它看起来是这样的,
class HeadersDTO {
}
tslib_1.__decorate([
class_validator_1.IsDefined(),
class_transformer_1.Expose({ name: 'custom-header' }),
tslib_1.__metadata("design:type", String)
], HeadersDTO.prototype, "custom-header", void 0);
exports.HeadersDTO = HeadersDTO;
当我没有通过 header ,
时出现以下错误[
ValidationError {
target: HeadersDTO { 'custom-header': undefined },
value: undefined,
property: 'custom-header',
children: [],
constraints: { isDefined: 'custom-header should not be null or undefined' }
}
]