CodePark/ questions / Pipes, DTOs & validation
START PRACTICINGPRACTICE
Backend question · NestJS › Pipes, DTOs & validation

Write a custom pipe that validates the body against a Zod (or similar) schema, and explain when you'd write a custom pipe instead of using ValidationPipe.

export class ZodValidationPipe implements PipeTransform {
  constructor(private schema: ZodSchema) {}

  transform(value: unknown, metadata: ArgumentMetadata) {
    const result = this.schema.safeParse(value);
    if (!result.success) {
      throw new BadRequestException(result.error.issues);
    }
    return result.data;
  }
}

@Post()
@UsePipes(new ZodValidationPipe(createCatSchema))
create(@Body() dto: CreateCatDto) {}

A custom pipe implements PipeTransform. Its transform method receives two things:

  • the incoming value
  • an ArgumentMetadata object. Its type says where the value came from (body, query, param or custom), and its metatype gives the declared type.

Whatever the pipe returns replaces the argument. If the pipe throws an HttpException, such as BadRequestException, the request ends with that error response.

In this example, the pipe parses the value with a schema and returns the parsed data. So any defaults and type conversions from the schema reach the handler.

Write a custom pipe when:

  • you prefer schema-based validation (like Zod) over class decorators
  • a value needs parsing specific to your domain, for example turning an id into a loaded entity
  • the validation logic doesn't fit class-validator

Otherwise, ValidationPipe covers most DTO validation.

  • Implement PipeTransform.transform(value, metadata).
  • ArgumentMetadata gives the type and the metatype of the value.
  • The pipe's return value replaces the argument.
  • Throw a BadRequestException on invalid input.
  • Use a custom pipe for schema validation or custom parsing.