2

I want to build a custom validator for NestJs (using v10) that will allow doing following

  1. Use Zod schema to validate
  2. Allows Creation of Dto from Zod Schema
  3. Works with File Upload (Nest's built-in FileInterceptor, UploadedFile & ParseFilePipe) etc

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

2 Answers 2

0

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

Sign up to request clarification or add additional context in comments.

Comments

0

the value parameter at transformer is just a plain object. I didn't get why you're expecting it to have the .schema property into it unless your request has such field

the role of your pipe is supposed to:

  1. read the schema attached as a metadata (via reflect API) of some class or to the instance of your pipe, as the docs shows here: https://docs.nestjs.com/pipes#binding-validation-pipes
  2. use zod to validate & transform some object into an instance of that class

1 Comment

To be clear, they're using a ZodValidationPipe I created in my personal project. That's why there's the expectation of the .schema property.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.