I want to build a custom validator for NestJs (using v10) that will allow doing following
Following is current implementation
Validation Pipe
// zod-validation.pipe.ts (bound globally from app module)
import { Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { ZodDtoClass } from '../utils/zod-dto.interface';
@Injectable()
export class ZodValidationPipe {
transform(value: Record<string, unknown>, metadata: ArgumentMetadata) {
const schemaClass: typeof ZodDtoClass = metadata.metatype! as unknown as typeof ZodDtoClass;
if (!schemaClass.schema) return;
const result = schemaClass.schema.safeParse(value);
if (!result.success) {
throw new BadRequestException(result.error.flatten());
}
return { data: result.data };
}
}
Dto
// create-feed.dto.ts
import { z } from 'zod';
import { ZodDtoClass } from '../../utils/zod-dto.interface';
const schema = z
.object({
title: z.string().min(5).max(35).nullish(),
body: z.string().max(140).nullish(),
})
.refine(
(d) => {
return !!(d.title || d.body);
},
{
path: ['title'],
message: "Title, Body and attachment can't be empty at the same time",
},
);
export class CreateFeedDto extends ZodDtoClass<typeof schema> {
static override schema = schema;
}
Controller method
@UseInterceptors(FileInterceptor('attachment'))
@Post('/create')
create(
@Body() createFeedDto: CreateFeedDto,
@UploadedFile(
new ParseFilePipe({
validators: [
new MaxFileSizeValidator({ maxSize: 5000000 }),
new FileTypeValidator({ fileType: '(jpg|png)$' }),
],
}),
)
attachment: Express.Multer.File,
) {
console.log({
createFeedDto: createFeedDto,
attachment,
});
return this.feedsService.create(createFeedDto);
}
After request from postman with all fields (with jpg
file). Following is the result I'm getting
{
createFeedDto: { data: { title: 'hello', body: 'This is body text' } },
attachment: undefined
}
FYI: I've already used all of the packages available that can do a similar thing & I found all of them have different problems and don't fulfill my requirements. So I want to create a new one
In your implementation of the pipe, in the if(!shcemaClass.schema)
you should use return value
to ensure that the original value is still returned rather than an undefined object. You really should read the docs on pipe and understand what my pipe is doing before saying it doesn't work