1import { ArgumentMetadata, Injectable, PipeTransform } from "@nestjs/common";
2import { z, type ZodTypeAny } from "zod";
3import { ApiError } from "../errors.js";
4
5
21@Injectable()
22
23
24
25
26export class ZodValidationPipe<T = unknown> implements PipeTransform<unknown, Promise<T>> {
27 constructor(private readonly schema: ZodTypeAny) {}
28
29 async transform(value: unknown, _metadata: ArgumentMetadata): Promise<T> {
30 const result = this.schema.safeParse(value);
31 if (!result.success) {
32 const details = result.error.issues.slice(0, 20).map((i) => ({
33 field: i.path.join("."),
34 issue: i.message
35 }));
36 throw ApiError.validation("Request validation failed.", details);
37 }
38 return result.data as T;
39 }
40}
41
42
43export function ZodValidate(schema: ZodTypeAny): ZodValidationPipe {
44 return new ZodValidationPipe(schema);
45}
46
47
51export function parseOrThrow<T>(schema: z.ZodType<T>, value: unknown): T {
52 const r = schema.safeParse(value);
53 if (!r.success) {
54 const details = r.error.issues.slice(0, 20).map((i) => ({ field: i.path.join("."), issue: i.message }));
55 throw ApiError.validation("Request validation failed.", details);
56 }
57 return r.data;
58}
59