From 01e562bd8baae67b4a920bae55fa826ded3922ec Mon Sep 17 00:00:00 2001 From: glebbash Date: Thu, 15 Feb 2024 11:58:24 +0200 Subject: [PATCH] feat(typed-headers): add support for passing custom ValidationPipe (#16) --- src/decorators/typed-headers.decorator.ts | 43 +++++++++++++---------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/decorators/typed-headers.decorator.ts b/src/decorators/typed-headers.decorator.ts index ed52d9f..04f6ac2 100644 --- a/src/decorators/typed-headers.decorator.ts +++ b/src/decorators/typed-headers.decorator.ts @@ -1,16 +1,19 @@ import { - BadRequestException, createParamDecorator, ExecutionContext, Headers, Type, + ValidationPipe, } from '@nestjs/common'; -import { plainToClass } from 'class-transformer'; -import { validateOrReject, ValidationError } from 'class-validator'; + +export type TypedHeadersOptions = { + validationPipe?: ValidationPipe; +}; export const TypedHeaders = + (options?: TypedHeadersOptions) => // eslint-disable-next-line @typescript-eslint/ban-types - () => (target: Object, propertyKey: string | symbol, parameterIndex: number) => { + (target: Object, propertyKey: string | symbol, parameterIndex: number) => { const types: Type[] | undefined = Reflect.getOwnMetadata( 'design:paramtypes', target, @@ -23,23 +26,25 @@ export const TypedHeaders = ); } + const validationPipe = options?.validationPipe ?? new ValidationPipe({ transform: true }); const paramType = types[parameterIndex]; + Headers()(target, propertyKey, parameterIndex); - HeaderSchema(paramType)(target, propertyKey, parameterIndex); + HeaderSchema({ paramType, validationPipe })(target, propertyKey, parameterIndex); }; -const HeaderSchema = createParamDecorator(async (value, ctx: ExecutionContext) => { - // Extract headers - const headers = ctx.switchToHttp().getRequest().headers; - - // Convert headers to DTO object - const dto = plainToClass(value, headers, { excludeExtraneousValues: true }); +const HeaderSchema = createParamDecorator( + async ( + options: { paramType: Type; validationPipe: ValidationPipe }, + ctx: ExecutionContext + ) => { + // Extract headers + const headers = ctx.switchToHttp().getRequest().headers; - // Validate - return validateOrReject(dto).then( - () => dto, - (err: ValidationError[]) => { - throw new BadRequestException(err.map((e) => Object.values(e.constraints as never)).flat()); - }, - ); -}); + // Validate and transform + return options.validationPipe.transform(headers, { + type: 'body', + metatype: options.paramType, + }); + } +);