### Install dependencies Source: https://github.com/benlorantfy/nestjs-zod/blob/main/CONTRIBUTING.md Install project dependencies using pnpm after cloning the repository. ```bash pnpm i ``` -------------------------------- ### Complete Exception Setup Example Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/exceptions.md This example demonstrates how to set up custom exception filters for ZodValidationException and ZodSerializationException in a NestJS application. It includes the necessary imports, filter implementations, and module configuration. ```typescript import { Module, Logger, Catch, ExceptionFilter, ArgumentsHost, HttpStatus } from '@nestjs/common'; import { APP_PIPE, APP_INTERCEPTOR, APP_FILTER } from '@nestjs/core'; import { ZodValidationPipe, ZodSerializerInterceptor, ZodValidationException, ZodSerializationException } from 'nestjs-zod'; import { ZodError } from 'zod'; @Catch(ZodValidationException) export class ZodValidationExceptionFilter implements ExceptionFilter { private readonly logger = new Logger('ZodValidation'); catch(exception: ZodValidationException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); const zodError = exception.getZodError(); const errors = zodError instanceof ZodError ? zodError.issues.map(issue => ({ field: issue.path.join('.'), message: issue.message, code: issue.code, })) : undefined; response.status(HttpStatus.BAD_REQUEST).json({ statusCode: HttpStatus.BAD_REQUEST, message: 'Validation failed', errors, }); } } @Catch(ZodSerializationException) export class ZodSerializationExceptionFilter implements ExceptionFilter { private readonly logger = new Logger('ZodSerialization'); catch(exception: ZodSerializationException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); this.logger.error('Response serialization failed', exception.getZodError()); response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ statusCode: HttpStatus.INTERNAL_SERVER_ERROR, message: 'Internal Server Error', }); } } @Module({ providers: [ { provide: APP_PIPE, useClass: ZodValidationPipe, }, { provide: APP_INTERCEPTOR, useClass: ZodSerializerInterceptor, }, { provide: APP_FILTER, useClass: ZodValidationExceptionFilter, }, { provide: APP_FILTER, useClass: ZodSerializationExceptionFilter, }, ], }) export class AppModule {} ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/benlorantfy/nestjs-zod/blob/main/packages/example-dual-zods/README.md Use this command to install all required project dependencies via pnpm. ```bash $ pnpm install ``` -------------------------------- ### Complete AppModule Example with Zod Integration Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/integration-setup.md This example demonstrates a complete AppModule setup for NestJS, integrating Zod for validation and serialization. It includes global pipes, interceptors, and custom exception filters for both validation and serialization errors. ```typescript import { Module, Logger, Catch, ExceptionFilter, ArgumentsHost, HttpStatus } from '@nestjs/common'; import { APP_PIPE, APP_INTERCEPTOR, APP_FILTER } from '@nestjs/core'; import { ZodValidationPipe, ZodSerializerInterceptor, ZodValidationException, ZodSerializationException } from 'nestjs-zod'; import { ZodError } from 'zod'; import { AppController } from './app.controller'; import { AppService } from './app.service'; // Custom validation exception filter @Catch(ZodValidationException) export class ZodValidationExceptionFilter implements ExceptionFilter { private readonly logger = new Logger('ZodValidation'); catch(exception: ZodValidationException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); const zodError = exception.getZodError(); let errors = undefined; if (zodError instanceof ZodError) { errors = zodError.issues.map(issue => ({ path: issue.path.join('.'), message: issue.message, code: issue.code, })); this.logger.warn(`Validation failed: ${zodError.message}`); } response.status(HttpStatus.BAD_REQUEST).json({ statusCode: HttpStatus.BAD_REQUEST, message: 'Validation failed', errors, timestamp: new Date().toISOString(), }); } } // Custom serialization exception filter @Catch(ZodSerializationException) export class ZodSerializationExceptionFilter implements ExceptionFilter { private readonly logger = new Logger('ZodSerialization'); catch(exception: ZodSerializationException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); this.logger.error( 'Response serialization failed', exception.getZodError(), ); // Return generic error (don't expose schema details) response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ statusCode: HttpStatus.INTERNAL_SERVER_ERROR, message: 'Internal Server Error', timestamp: new Date().toISOString(), }); } } @Module({ controllers: [AppController], providers: [ AppService, // Global pipes { provide: APP_PIPE, useClass: ZodValidationPipe, }, // Global interceptors { provide: APP_INTERCEPTOR, useClass: ZodSerializerInterceptor, }, // Global exception filters { provide: APP_FILTER, useClass: ZodValidationExceptionFilter, }, { provide: APP_FILTER, useClass: ZodSerializationExceptionFilter, }, ], }) export class AppModule {} ``` -------------------------------- ### Install @nestjs/swagger (Optional) Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/integration-setup.md Install the @nestjs/swagger package if you plan to use Swagger/OpenAPI support. ```bash npm install @nestjs/swagger ``` -------------------------------- ### Complete NestJS-Zod OpenAPI Integration Example Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-openapi.md A comprehensive example showing the full integration of nestjs-zod with SwaggerModule, including document creation and setup. ```typescript import { NestFactory } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { cleanupOpenApiDoc } from 'nestjs-zod'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); // Build OpenAPI documentation const config = new DocumentBuilder() .setTitle('Books API') .setDescription('API for managing books') .setVersion('1.0.0') .addTag('books') .build(); // Create the document const document = SwaggerModule.createDocument(app, config); // Clean up and apply nestjs-zod transformations const cleanedDocument = cleanupOpenApiDoc(document); // Setup Swagger with cleaned document SwaggerModule.setup('api-docs', app, cleanedDocument); await app.listen(3000); console.log('API documentation available at http://localhost:3000/api-docs'); } bootstrap(); ``` -------------------------------- ### Install nestjs-zod and zod Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/integration-setup.md Install the core nestjs-zod and zod packages using npm. ```bash npm install nestjs-zod zod ``` -------------------------------- ### Compile and Run Application Source: https://github.com/benlorantfy/nestjs-zod/blob/main/packages/example-dual-zods/README.md Commands to start the application in development, watch, or production modes. ```bash # development $ pnpm run start # watch mode $ pnpm run start:dev # production mode $ pnpm run start:prod ``` -------------------------------- ### Basic NestJS-Zod OpenAPI Setup Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-openapi.md Demonstrates the basic setup for integrating nestjs-zod with SwaggerModule in a NestJS application. ```typescript import { cleanupOpenApiDoc } from 'nestjs-zod'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; // In your main.ts or bootstrap function const document = SwaggerModule.createDocument(app, new DocumentBuilder() .setTitle('API') .setVersion('1.0') .build(), ); SwaggerModule.setup('api', app, cleanupOpenApiDoc(document)); ``` -------------------------------- ### Deploy via Mau Source: https://github.com/benlorantfy/nestjs-zod/blob/main/packages/example-esm/README.md Installs the Mau CLI globally and deploys the application to AWS. ```bash $ pnpm install -g @nestjs/mau $ mau deploy ``` -------------------------------- ### Install nestjs-zod and Zod Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/quick-reference.md Install the core nestjs-zod and zod packages. Optionally, install @nestjs/swagger for API documentation integration. ```bash npm install nestjs-zod zod npm install -D @nestjs/swagger # Optional ``` -------------------------------- ### Apply cleanupOpenApiDoc to Swagger setup Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Use this diff to integrate cleanupOpenApiDoc into your existing SwaggerModule setup. ```diff const openApiDoc = SwaggerModule.createDocument(app, new DocumentBuilder() .setTitle('Example API') .setDescription('Example API description') .setVersion('1.0') .build(), ); - SwaggerModule.setup('api', app, openApiDoc); + SwaggerModule.setup('api', app, cleanupOpenApiDoc(openApiDoc)); ``` -------------------------------- ### Install nestjs-zod Package Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Install the nestjs-zod package and its peer dependency zod. Ensure zod version is compatible. ```bash npm install nestjs-zod # Note: zod ^3.25.0 || ^4.0.0 is also required ``` -------------------------------- ### Run Automatic Setup CLI Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Executes a codemod to automatically configure the validation pipe, serialization interceptor, exception filter, and Swagger integration. ```bash npx nestjs-zod-cli /path/to/nestjs/project ``` -------------------------------- ### Setup cleanupOpenApiDoc in NestJS Application Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-openapi.md Demonstrates how to integrate cleanupOpenApiDoc into a NestJS application's Swagger setup. Apply the cleanup function to the document before passing it to SwaggerModule.setup. ```typescript import { NestFactory, } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder, } from '@nestjs/swagger'; import { cleanupOpenApiDoc } from 'nestjs-zod'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); const config = new DocumentBuilder() .setTitle('My API') .setDescription('My API description') .setVersion('1.0') .build(); const document = SwaggerModule.createDocument(app, config); // Apply cleanupOpenApiDoc before setup SwaggerModule.setup('api', app, cleanupOpenApiDoc(document)); await app.listen(3000); } bootstrap(); ``` -------------------------------- ### Generated OpenAPI Response Schema Example Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Example of OpenAPI documentation generated by the @ZodResponse decorator for a successful response. ```json { "responses": { "200": { "description": "Book", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BookDto_Output" } } } } } } ``` -------------------------------- ### Creating and Using a UserDto Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/types.md Demonstrates how to create a `UserDto` class from a Zod schema using `createZodDto`. Includes type inference and manual validation examples. ```typescript import { createZodDto } from 'nestjs-zod'; import { z } from 'zod'; const UserSchema = z.object({ id: z.number(), name: z.string(), email: z.string().email(), }); class UserDto extends createZodDto(UserSchema) {} // Type inference from schema type User = z.infer; // Manual validation const data = UserDto.create({ id: 1, name: 'John', email: 'john@example.com' }); ``` -------------------------------- ### NestJS-Zod File Structure Example Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/quick-reference.md Illustrates a typical project structure for a NestJS application utilizing nestjs-zod for validation and serialization. ```tree src/ ├── app.module.ts # Setup pipes/interceptors ├── main.ts # Swagger setup ├── common/ │ ├── filters/ │ │ └── zod-exception.filter.ts │ └── pipes/ │ └── validation.ts ├── users/ │ ├── users.controller.ts │ ├── users.service.ts │ └── users.dto.ts # All DTOs here └── products/ ├── products.controller.ts ├── products.service.ts └── products.dto.ts ``` -------------------------------- ### Setup Swagger/OpenAPI Documentation Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/quick-reference.md Integrate nestjs-zod with Swagger by creating a DocumentBuilder, generating the document, and setting up Swagger UI. Use cleanupOpenApiDoc to ensure compatibility. ```typescript // main.ts import { NestFactory } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { cleanupOpenApiDoc } from 'nestjs-zod'; async function bootstrap() { const app = await NestFactory.create(AppModule); const config = new DocumentBuilder() .setTitle('API') .setVersion('1.0') .build(); const doc = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api', app, cleanupOpenApiDoc(doc)); await app.listen(3000); } bootstrap(); ``` -------------------------------- ### Clone the forked repository Source: https://github.com/benlorantfy/nestjs-zod/blob/main/CONTRIBUTING.md Clone your forked repository to your local machine to start making changes. ```bash git clone git@github.com:{your_username}/nestjs-zod.git ``` -------------------------------- ### ZodResponse Decorator Example (Array Response) Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Example of using `ZodResponse` for an array response type. It ensures the array elements match the specified Zod schema. ```typescript function ZodResponse>({ status, description, type }: { status?: number, description?: string, type: [ZodDto & { io: "input" }] }): (target: object, propertyKey?: string | symbol, descriptor?: Pick Array>|Promise>>>, 'value'>) => void ``` -------------------------------- ### Example: Make All Properties Required with RequiredBy Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/types.md Demonstrates how to use the RequiredBy utility type to make all properties of a given object type required. ```typescript type Props = { name?: string; age?: number; visible?: boolean; }; // Make all properties required type RequiredProps = RequiredBy; // Result: { name: string; age: number; visible: boolean; } ``` -------------------------------- ### NestJS-Zod OpenAPI Setup with Explicit Version Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-openapi.md Illustrates how to explicitly set the OpenAPI version when setting up Swagger with nestjs-zod. ```typescript // For OpenAPI 3.0 compatibility SwaggerModule.setup('api', app, cleanupOpenApiDoc(document, { version: '3.0' })); // For OpenAPI 3.1 SwaggerModule.setup('api', app, cleanupOpenApiDoc(document, { version: '3.1' })); // Auto-detect from document (default) SwaggerModule.setup('api', app, cleanupOpenApiDoc(document, { version: 'auto' })); ``` -------------------------------- ### API Response Documentation Without @ZodResponse Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Illustrates the manual setup required without @ZodResponse, including explicit serialization, status code, documentation, and return type annotations. ```typescript @Get(':id') @ZodSerializerDto(BookDto) // 1. Serialization @HttpCode(200) // 2. Status code @ApiResponse({ // 3. Documentation status: 200, description: 'Get book', type: BookDto, // 4. Duplicated type }) getBook(id: string): BookDto { // 5. Return type (must match manually) return { id: 1, title: 'Book', author: 'Author' }; } ``` -------------------------------- ### ZodResponse Decorator Example (Single Response) Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Example of using `ZodResponse` for a single response type. It ensures the response data matches the specified Zod schema. ```typescript function ZodResponse({ status, description, type }: { status?: number, description?: string, type: ZodDto & { io: "input" } }): (target: object, propertyKey?: string | symbol, descriptor?: Pick input|Promise>>, 'value'>) => void ``` -------------------------------- ### Get Book with Error Response Handling Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Illustrates how to document both a successful response using @ZodResponse and a specific error response (e.g., 404 Not Found) using @ApiResponse. ```APIDOC ## GET /:id (with Error Handling) ### Description Retrieves a book by its ID. Handles cases where the book is found and when it is not found. ### Method GET ### Endpoint /:id ### Parameters #### Path Parameters - **id** (string) - Required - The ID of the book to retrieve. ### Response #### Success Response (200) - **id** (number) - The unique identifier for the book. - **title** (string) - The title of the book. - **author** (string) - The name of the author. #### Error Response (404) - **description**: 'Book not found' ### Request Example ```json { "example": "Not applicable for GET request without a body" } ``` ### Response Example ```json { "example": { "id": 1, "title": "Book", "author": "Author" } } ``` ``` -------------------------------- ### Get Book with Author Details Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Demonstrates how to use @ZodResponse to document a successful GET request that returns nested object details, including author information. ```APIDOC ## GET /:id ### Description Retrieves a book along with its author's details. ### Method GET ### Endpoint /:id ### Parameters #### Path Parameters - **id** (string) - Required - The ID of the book to retrieve. ### Response #### Success Response (200) - **id** (number) - The unique identifier for the book. - **title** (string) - The title of the book. - **author** (object) - An object containing the author's details. - **id** (number) - The unique identifier for the author. - **name** (string) - The name of the author. ### Request Example ```json { "example": "Not applicable for GET request without a body" } ``` ### Response Example ```json { "example": { "id": 1, "title": "The Great Gatsby", "author": { "id": 1, "name": "F. Scott Fitzgerald" } } } ``` ``` -------------------------------- ### Example: Make Specific Properties Required with RequiredBy Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/types.md Shows how to use the RequiredBy utility type to make only a subset of properties in an object type required. ```typescript type Props = { name?: string; age?: number; visible?: boolean; }; // Make only specific properties required type PartiallyRequired = RequiredBy; // Result: { name: string; age: number; visible?: boolean; } ``` -------------------------------- ### Setup Swagger/OpenAPI with nestjs-zod Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/integration-setup.md Configure SwaggerModule in your main.ts file and use cleanupOpenApiDoc from nestjs-zod to ensure compatibility with nestjs-zod's serialization. ```typescript // main.ts import { NestFactory } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { cleanupOpenApiDoc } from 'nestjs-zod'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); const config = new DocumentBuilder() .setTitle('My API') .setDescription('My API description') .setVersion('1.0.0') .addTag('default') .build(); const document = SwaggerModule.createDocument(app, config); // Apply cleanupOpenApiDoc BEFORE setup SwaggerModule.setup('api-docs', app, cleanupOpenApiDoc(document)); await app.listen(3000); console.log('API available at http://localhost:3000'); console.log('Swagger UI at http://localhost:3000/api-docs'); } bootstrap(); ``` -------------------------------- ### Dockerfile for NestJS Application Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/integration-setup.md This Dockerfile sets up a production-ready environment for a NestJS application using Node.js 20 Alpine. It copies package files, installs production dependencies, copies the application code, builds the application, exposes port 3000, and defines the command to run the application. ```dockerfile FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build EXPOSE 3000 CMD ["node", "dist/main.js"] ``` -------------------------------- ### Define Nested Zod Schemas and Use @ZodResponse Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Demonstrates defining nested Zod schemas for authors and books, creating a DTO, and using @ZodResponse to document the success response for a GET endpoint. ```typescript const AuthorSchema = z.object({ id: z.number(), name: z.string(), }).meta({ id: 'Author' }); const BookSchema = z.object({ id: z.number(), title: z.string(), author: AuthorSchema, }).meta({ id: 'Book' }); class BookDto extends createZodDto(BookSchema) {} @Get(':id') @ZodResponse({ status: 200, description: 'Get book with author details', type: BookDto, }) getBook(id: string) { return { id: 1, title: 'The Great Gatsby', author: { id: 1, name: 'F. Scott Fitzgerald', }, }; } ``` -------------------------------- ### Basic Global ZodValidationPipe Setup Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-pipe.md Configure the ZodValidationPipe globally in your AppModule to automatically validate all incoming request data. ```typescript import { Module } from '@nestjs/common'; import { APP_PIPE } from '@nestjs/core'; import { ZodValidationPipe } from 'nestjs-zod'; import { createZodDto } from 'nestjs-zod'; import { z } from 'zod'; const CreateUserSchema = z.object({ email: z.string().email(), name: z.string().min(1).max(100), }); class CreateUserDto extends createZodDto(CreateUserSchema) {} @Module({ providers: [ { provide: APP_PIPE, useClass: ZodValidationPipe, }, ], }) export class AppModule {} ``` -------------------------------- ### ZodSerializerDto Array Serialization Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Examples of serializing arrays using either the array syntax or an array DTO. ```typescript class BookDto extends createZodDto(z.object({ title: string() })) {} @Controller('books') export class BooksController { constructor() {} @ZodSerializerDto([BookDto]) getBooks() { return [{ title: 'The Martian' }, { title: 'Hail Marry' }]; } } ``` ```typescript class BookListDto extends createZodDto(z.array(z.object({ title: string() }))) {} @Controller('books') export class BooksController { constructor() {} @ZodSerializerDto(BookListDto) getBooks() { return [{ title: 'The Martian' }, { title: 'Hail Marry' }]; } } ``` -------------------------------- ### Integration with ZodValidationPipe Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Demonstrates the seamless integration of `@ZodResponse` with `ZodValidationPipe`. This setup ensures that both incoming request data (validated by `ZodValidationPipe`) and outgoing response data (validated by `ZodSerializerInterceptor` via `@ZodResponse`) are properly validated against their respective Zod schemas. ```APIDOC ## Integration with ZodValidationPipe `@ZodResponse` works seamlessly with `ZodValidationPipe`: ```typescript @Post() @ZodResponse({ status: 201, type: UserDto, }) createUser(@Body() createUserDto: CreateUserDto) { // Input validated by ZodValidationPipe // Output validated by ZodSerializerInterceptor (via @ZodResponse) return { id: 1, ...createUserDto }; } ``` ``` -------------------------------- ### Conditional Serialization with ZodDto Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-serializer.md Implement conditional serialization by defining different schemas for different user roles. This example shows how to expose different fields for admin and public user views. ```typescript const AdminUserSchema = z.object({ id: z.number(), name: z.string(), email: z.string(), role: z.string(), lastLoginAt: z.date().optional(), }); const PublicUserSchema = z.object({ id: z.number(), name: z.string(), // email and lastLoginAt are hidden }); class AdminUserDto extends createZodDto(AdminUserSchema) {} class PublicUserDto extends createZodDto(PublicUserSchema) {} @Controller('users') export class UsersController { @Get('admin/:id') @ZodSerializerDto(AdminUserDto) getAdminUser(id: number) { return { id: 1, name: 'Admin', email: 'admin@example.com', role: 'admin', lastLoginAt: new Date() }; } @Get(':id') @ZodSerializerDto(PublicUserDto) getPublicUser(id: number) { return { id: 1, name: 'User', email: 'user@example.com', role: 'user', lastLoginAt: new Date() }; } } ``` -------------------------------- ### Validating Query Parameters with Zod DTO and Transformations Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-pipe.md Use Zod schemas with transformations to validate and convert query parameters into the desired types. This example validates and transforms 'page' and 'limit' into numbers. ```typescript import { Controller, Get, Query } from '@nestjs/common'; import { z } from 'zod'; import { createZodDto } from 'nestjs-zod'; const PaginationSchema = z.object({ page: z.string().transform(Number).pipe(z.number().int().positive()), limit: z.string().transform(Number).pipe(z.number().int().positive()), search: z.string().optional(), }); class PaginationDto extends createZodDto(PaginationSchema) {} @Controller('products') export class ProductsController { @Get() list(@Query() query: PaginationDto) { // query is validated and transformed // type: { page: number; limit: number; search?: string } return []; } } ``` -------------------------------- ### Run nestjs-zod-cli Source: https://github.com/benlorantfy/nestjs-zod/blob/main/packages/cli/README.md Use this command to automatically set up and integrate nestjs-zod in your nestjs project. Provide the path to your nestjs project as an argument. ```bash nestjs-zod-cli /path/to/nestjs/project ``` -------------------------------- ### ZodValidationExceptionFilter Usage Example with Logging Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/exceptions.md An example of a NestJS exception filter that catches ZodValidationException, logs the error, and returns a structured JSON response. ```typescript import { Catch, ArgumentsHost, ExceptionFilter, Logger } from '@nestjs/common'; import { ZodValidationException } from 'nestjs-zod'; import { ZodError } from 'zod'; @Catch(ZodValidationException) export class ZodValidationExceptionFilter implements ExceptionFilter { private readonly logger = new Logger(ZodValidationExceptionFilter.name); catch(exception: ZodValidationException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const request = ctx.getRequest(); const response = ctx.getResponse(); const zodError = exception.getZodError(); this.logger.error( `Validation error on ${request.method} ${request.url}`, zodError, ); if (zodError instanceof ZodError) { response.status(400).json({ statusCode: 400, message: 'Validation failed', path: request.url, timestamp: new Date().toISOString(), errors: zodError.issues.map(({ path, message, code }) => ({ field: path.join('.'), message, code, })), }); } else { response.status(400).json({ statusCode: 400, message: 'Validation failed', }); } } } ``` -------------------------------- ### ZodSchemaDeclarationException Filter Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Example of an exception filter to catch ZodSchemaDeclarationException. ```typescript @Catch(ZodSchemaDeclarationException) export class ZodSchemaDeclarationExceptionFilter implements ExceptionFilter { catch(exception: ZodSchemaDeclarationException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); response.status(500).json({ statusCode: 500, message: 'Missing nestjs-zod schema declaration', }); } } ``` -------------------------------- ### ZodValidationException Filter Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Example of an exception filter to catch ZodValidationException. ```typescript @Catch(ZodValidationException) export class ZodValidationExceptionFilter implements ExceptionFilter { catch(exception: ZodValidationException) { exception.getZodError() // -> ZodError } } ``` -------------------------------- ### ZodSerializerDto Usage Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Example of using ZodSerializerDto to strip sensitive data from a controller response. ```typescript const UserSchema = z.object({ username: string() }) class UserDto extends createZodDto(UserSchema) {} @Controller('user') export class UserController { constructor(private readonly userService: UserService) {} @ZodSerializerDto(UserDto) getUser(id: number) { return this.userService.findOne(id) } } ``` -------------------------------- ### Use ZodResponse decorator Source: https://github.com/benlorantfy/nestjs-zod/blob/main/README.md Recommended approach for response documentation that automatically handles schema output versions. ```ts @ZodResponse({ type: MyDto // <-- No need to do `.Output` here }) ``` -------------------------------- ### Execute Tests Source: https://github.com/benlorantfy/nestjs-zod/blob/main/packages/example-dual-zods/README.md Commands to run unit tests, end-to-end tests, or generate test coverage reports. ```bash # unit tests $ pnpm run test # e2e tests $ pnpm run test:e2e # test coverage $ pnpm run test:cov ``` -------------------------------- ### Extracting Input and Output Types with Zod v4 Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/types.md Demonstrates how to differentiate between the input type (what the schema accepts) and the output type (what the schema produces) using `z.input` and `z.output` for Zod schemas that include transformations. ```typescript import { z } from 'zod'; const stringToDate = z.string().datetime().transform(d => new Date(d)); const EventSchema = z.object({ id: z.number(), date: stringToDate, }); // Input type (what the schema accepts) type EventInput = z.input; // Result: { id: number; date: string } // Output type (what the schema produces) type EventOutput = z.output; // Result: { id: number; date: Date } ``` -------------------------------- ### Manual Data Validation with createZodDto Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/utilities-and-helpers.md Demonstrates how to manually validate unknown data against a DTO schema created with `createZodDto`. It shows using `schema.parse()` for validation and error handling, or the DTO's `create()` method for combined validation and instantiation. ```typescript import { createZodDto } from 'nestjs-zod'; import { z } from 'zod'; class UserDto extends createZodDto(z.object({ name: z.string(), email: z.string().email(), })) {} // Manual validation function validateUserData(data: unknown) { try { return UserDto.schema.parse(data); } catch (error) { throw new Error(`Validation failed: ${error}`); } } // Or use the DTO's create method function validateAndCreate(data: unknown) { return UserDto.create(data); } ``` -------------------------------- ### Basic Usage of ZodResponse Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Demonstrates how to apply the ZodResponse decorator to a controller method to define the expected response schema and status code. ```APIDOC ## GET /books/:id ### Description Retrieves the details of a specific book. ### Method GET ### Endpoint /books/:id ### Parameters #### Path Parameters - **id** (string) - Required - The ID of the book to retrieve. ### Response #### Success Response (200) - **id** (number) - The unique identifier of the book. - **title** (string) - The title of the book. - **author** (string) - The author of the book. #### Response Example { "id": 1, "title": "The Great Gatsby", "author": "F. Scott Fitzgerald" } ``` -------------------------------- ### Create Custom Exception Creator with ZodExceptionCreator Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/types.md Provides an example of implementing ZodExceptionCreator to generate a BadRequestException with specific error details for Zod validation failures. ```typescript import { createZodValidationPipe } from 'nestjs-zod'; import { BadRequestException } from '@nestjs/common'; import { ZodError } from 'zod'; const CustomExceptionCreator: ZodExceptionCreator = (error) => { if (error instanceof ZodError) { return new BadRequestException({ message: 'Validation failed', issues: error.issues, }); } return new BadRequestException('Unknown validation error'); }; const CustomPipe = createZodValidationPipe({ createValidationException: CustomExceptionCreator, }); ``` -------------------------------- ### Using Explicit Output Schemas with OpenAPI Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Demonstrates how to explicitly use output schemas with OpenAPI decorators. The `.Output` property of a Zod schema can be used to specify the output type. ```typescript // Without @ZodResponse, explicit output schema: @ApiResponse({ type: BookDto.Output }) ``` ```typescript // With @ZodResponse: @ZodResponse({ type: BookDto }) ``` -------------------------------- ### OpenAPI Documentation Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/quick-reference.md Use `cleanupOpenApiDoc` to refine your OpenAPI documentation. The `version` option allows specifying the OpenAPI version. ```typescript cleanupOpenApiDoc(doc, { version?: '3.0' | '3.1' | 'auto' }) ``` -------------------------------- ### OpenAPI Schema Structure with Reusable Schemas Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-openapi.md Illustrates the resulting OpenAPI schema structure when using .meta({ id: 'SchemaName' }) for reusable schemas. It shows how 'Address' is defined in components.schemas and referenced by '$ref' in 'Person' and 'Company'. ```json { "components": { "schemas": { "Address": { /* ... */ }, "Person": { "type": "object", "properties": { "address": { "$ref": "#/components/schemas/Address" } } }, "Company": { "type": "object", "properties": { "headquarters": { "$ref": "#/components/schemas/Address" } } } } } } ``` -------------------------------- ### Custom Serializer Interceptor with NestJS Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-serializer.md Create a custom serializer interceptor using `createZodSerializerInterceptor` to globally apply Zod-based serialization. This example demonstrates how to enable input reporting. ```typescript import { APP_INTERCEPTOR } from '@nestjs/core'; import { createZodSerializerInterceptor } from 'nestjs-zod'; const CustomSerializerInterceptor = createZodSerializerInterceptor({ reportInput: true, // Zod v4 only }); @Module({ providers: [ { provide: APP_INTERCEPTOR, useClass: CustomSerializerInterceptor, }, ], }) export class AppModule {} ``` -------------------------------- ### Migrate from ZodGuard to ZodValidationPipe Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/deprecated-apis.md This snippet demonstrates the migration from using `ZodGuard` for validation to the recommended `ZodValidationPipe`. It shows how to apply the pipe globally or per-route for DTO validation. ```typescript import { UseGuards } from '@nestjs/common'; import { ZodGuard } from 'nestjs-zod'; @UseGuards(new ZodGuard('body', CredentialsSchema)) async signIn() {} ``` ```typescript import { UsePipes } from '@nestjs/common'; import { ZodValidationPipe } from 'nestjs-zod'; @UsePipes(ZodValidationPipe) async signIn(@Body() credentials: CredentialsDto) {} ``` ```typescript import { UseGuards } from '@nestjs/common'; import { ZodGuard } from 'nestjs-zod'; // Still available but not recommended @UseGuards(new ZodGuard('body', CredentialsSchema)) async signIn() {} ``` -------------------------------- ### Validating URL Parameters with Zod DTO Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-pipe.md Validate URL parameters using a Zod DTO. This example ensures that the 'id' parameter in the URL is a valid UUID string. ```typescript import { Controller, Get, Param } from '@nestjs/common'; import { z } from 'zod'; import { createZodDto } from 'nestjs-zod'; const GetUserParamsSchema = z.object({ id: z.string().uuid(), }); class GetUserParamsDto extends createZodDto(GetUserParamsSchema) {} @Controller('users') export class UsersController { @Get(':id') getUser(@Param() params: GetUserParamsDto) { // params.id is validated as a UUID string return { id: params.id }; } } ``` -------------------------------- ### DTO Creation Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/quick-reference.md Use `createZodDto` to generate DTOs from Zod schemas, with an optional codec option for advanced use cases. ```APIDOC ## DTO Creation ### `createZodDto(schema, options?: { codec?: boolean })` **Description**: Creates a DTO class from a Zod schema. **Parameters**: - **schema**: The Zod schema to create the DTO from. - **options**: Optional configuration object. - **codec**: (boolean) - If true, enables codec functionality for advanced transformations. ``` -------------------------------- ### Using OpenAPI Output Schemas with Zod Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Demonstrates how to explicitly use output schemas with Zod v4 schemas for OpenAPI integration. You can either use the `.Output` property directly with `@ApiResponse` or rely on `@ZodResponse` to automatically infer the output schema if available. ```APIDOC ## Using OpenAPI Output Schemas with Zod For Zod v4 schemas, you can use the `.Output` property to explicitly use output schemas: ```typescript // Without @ZodResponse, explicit output schema: @ApiResponse({ type: BookDto.Output }) // With @ZodResponse: @ZodResponse({ type: BookDto }) // Automatically uses output schema if available ``` ``` -------------------------------- ### Nested Object Serialization with ZodDto Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-serializer.md Define nested schemas using Zod and apply them to DTOs for response serialization. This example shows how to serialize a Book object with a nested Author object. ```typescript const AuthorSchema = z.object({ id: z.number(), name: z.string(), }).meta({ id: 'Author' }); const BookSchema = z.object({ id: z.number(), title: z.string(), author: AuthorSchema, }).meta({ id: 'Book' }); class BookDto extends createZodDto(BookSchema) {} @Controller('books') export class BooksController { @Get(':id') @ZodSerializerDto(BookDto) getBook(id: number) { return { id: 1, title: 'The Great Gatsby', author: { id: 1, name: 'F. Scott Fitzgerald' }, }; } } ``` -------------------------------- ### Example of Triggering ZodSchemaDeclarationException Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/exceptions.md Demonstrates a scenario where ZodSchemaDeclarationException is thrown. This occurs when a controller method's parameter (e.g., @Body()) is not typed with a Zod DTO, and strictSchemaDeclaration is enabled in the validation pipe. ```typescript @Post() create(@Body() data: any) {} // Error: Missing ZodDto // ZodSchemaDeclarationException is thrown ``` -------------------------------- ### Find zodV3ToOpenAPI Usage Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/deprecated-apis.md Use this command to identify all occurrences of the `zodV3ToOpenAPI` function in your project. ```bash grep -r "zodV3ToOpenAPI" src/ ``` -------------------------------- ### Nested Objects Serialization Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-serializer.md Demonstrates how to define and use nested Zod schemas for serialization, ensuring complex object structures are correctly handled. ```APIDOC ## GET /books/:id ### Description Retrieves a book with its author details, serialized according to the `BookDto`. ### Method GET ### Endpoint /books/:id ### Parameters #### Path Parameters - **id** (number) - Required - The ID of the book to retrieve. ### Response #### Success Response (200) - **id** (number) - The unique identifier of the book. - **title** (string) - The title of the book. - **author** (object) - An object containing the author's details. - **id** (number) - The unique identifier of the author. - **name** (string) - The name of the author. ### Response Example { "id": 1, "title": "The Great Gatsby", "author": { "id": 1, "name": "F. Scott Fitzgerald" } } ``` -------------------------------- ### Test Setup with Global nestjs-zod Pipes and Interceptors Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/integration-setup.md Configure NestJS testing module to use ZodValidationPipe and ZodSerializerInterceptor globally. This is useful for ensuring that tests run with the same validation and serialization logic as the production environment. ```typescript import { Test } from '@nestjs/testing'; import { ZodValidationPipe, ZodSerializerInterceptor } from 'nestjs-zod'; const moduleRef = await Test.createTestingModule({ controllers: [MyController], providers: [ MyService, { provide: APP_PIPE, useClass: ZodValidationPipe, }, { provide: APP_INTERCEPTOR, useClass: ZodSerializerInterceptor, }, ], }).compile(); ``` -------------------------------- ### Using createZodSerializerInterceptor Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-serializer.md Configures a global serializer interceptor using `createZodSerializerInterceptor` to automatically serialize responses based on Zod schemas. ```APIDOC ## Global Configuration ### Description This snippet shows how to set up `createZodSerializerInterceptor` as a global interceptor in your NestJS application module to automatically apply Zod-based serialization to all outgoing responses. ### Usage Import `createZodSerializerInterceptor` and provide it via `APP_INTERCEPTOR` in your `AppModule`. ### Configuration Options - **reportInput** (boolean, optional): If true, reports the input data to the console (Zod v4 only). ### Example ```typescript import { Module } from '@nestjs/common'; import { APP_INTERCEPTOR } from '@nestjs/core'; import { createZodSerializerInterceptor } from 'nestjs-zod'; const CustomSerializerInterceptor = createZodSerializerInterceptor({ reportInput: true, // Example option }); @Module({ providers: [ { provide: APP_INTERCEPTOR, useClass: CustomSerializerInterceptor, }, ], }) export class AppModule {} ``` ``` -------------------------------- ### Example of Missing Schema Declaration Error Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/integration-setup.md In development mode with strict schema declaration enabled, a controller method that does not define a ZodDto for its body parameter will throw an error. This highlights the importance of defining schemas for all DTOs. ```typescript @Post() create(@Body() data: any) {} // Error in development ``` -------------------------------- ### Serialization Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/quick-reference.md Leverage interceptors and decorators for seamless data serialization and transformation. ```APIDOC ## Serialization ### `ZodSerializerInterceptor` **Description**: A pre-made interceptor for serializing response data according to Zod schemas. ### `createZodSerializerInterceptor(options)` **Description**: Creates a custom serializer interceptor with configurable options. **Parameters**: - **options**: Configuration object for the interceptor. - `reportInput`: (boolean) - If true, includes input data in error reports. ### `ZodSerializerDto(dto)` **Description**: Decorator to apply serialization logic to a DTO. ### `ZodResponse({ type, status?, description? })` **Description**: Combined decorator for defining response types, status codes, and descriptions for OpenAPI. **Parameters**: - **type**: The DTO type for the response. - **status**: (Optional) The HTTP status code for the response. - **description**: (Optional) A description of the response. ### `ZodSerializationException` **Description**: Exception thrown when data serialization fails. ``` -------------------------------- ### Configuration Option Interfaces Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/GENERATION_REPORT.md Interfaces defining configuration options for various parts of the library. ```APIDOC ## Configuration Option Interfaces ### Description Interfaces that define the structure for configuration options used throughout the library, such as for validation pipes and serializers. ### Available Interfaces - Interfaces for `createZodValidationPipe` options. - Interfaces for `createZodSerializerInterceptor` options. ``` -------------------------------- ### Serialization with Custom Date Transformation Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-serializer.md Utilize Zod codecs to define custom transformations, such as converting ISO strings to Date objects during decoding and vice-versa during serialization. This example shows a stringToDate codec for date handling. ```typescript const stringToDate = z.codec( z.string().datetime(), z.date(), { decode: (isoString) => new Date(isoString), encode: (date) => date.toISOString(), // Called during serialization } ); class EventDto extends createZodDto(z.object({ id: z.number(), name: z.string(), date: stringToDate, }), { codec: true }) {} @Controller('events') export class EventsController { @Get() @ZodSerializerDto(EventDto) listEvents() { return [ { id: 1, name: 'Event 1', date: new Date('2025-06-16') }, ]; // Response: [{ "id": 1, "name": "Event 1", "date": "2025-06-16T00:00:00.000Z" }] } } ``` -------------------------------- ### Environment-Specific Configuration with nestjs-zod Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/integration-setup.md Configure validation pipes and serializer interceptors based on the environment (development or production). In development, strict schema declaration and input reporting are enabled. This setup is applied globally using APP_PIPE and APP_INTERCEPTOR. ```typescript import { createZodValidationPipe, createZodSerializerInterceptor } from 'nestjs-zod'; const isDev = process.env.NODE_ENV === 'development'; const isProd = process.env.NODE_ENV === 'production'; export function getValidationPipe() { return createZodValidationPipe({ strictSchemaDeclaration: isDev, // Strict in development }); } export function getSerializerInterceptor() { return createZodSerializerInterceptor({ reportInput: isDev, // Include input details in dev }); } @Module({ providers: [ { provide: APP_PIPE, useClass: getValidationPipe(), }, { provide: APP_INTERCEPTOR, useClass: getSerializerInterceptor(), }, ], }) export class AppModule {} ``` -------------------------------- ### API Response Documentation With @ZodResponse Source: https://github.com/benlorantfy/nestjs-zod/blob/main/_autodocs/api-reference-response.md Highlights the simplified approach using @ZodResponse, where the type definition serves as a single source of truth for documentation and response structure. ```typescript @Get(':id') @ZodResponse({ status: 200, description: 'Get book', type: BookDto, // Single source of truth }) getBook(id: string) { return { id: 1, title: 'Book', author: 'Author' }; } ```