|
| 1 | +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; |
1 | 2 | import { z } from 'zod'; |
2 | 3 |
|
3 | 4 | /** |
4 | | - * Zod schema for CreateUserDto |
| 5 | + * Zod schema for AddressDto (nested) |
5 | 6 | */ |
6 | | -const createUserSchema = z.object({ |
| 7 | +export const addressSchema = z.object({ |
| 8 | + street: z.string().min(1, 'Street is required'), |
| 9 | + city: z.string().min(1, 'City is required'), |
| 10 | + zipCode: z.string().regex(/^\d{5}(-\d{4})?$/, 'Invalid zip code format'), |
| 11 | + country: z.string().min(2).max(2, 'Country must be ISO 3166-1 alpha-2 code'), |
| 12 | +}); |
| 13 | + |
| 14 | +/** |
| 15 | + * Nested DTO for address with Swagger documentation. |
| 16 | + * Uses `implements z.infer<typeof schema>` to ensure type safety. |
| 17 | + */ |
| 18 | +export class AddressDto implements z.infer<typeof addressSchema> { |
| 19 | + static schema = addressSchema; |
| 20 | + |
| 21 | + @ApiProperty({ description: 'Street address', example: '123 Main St' }) |
| 22 | + declare street: string; |
| 23 | + |
| 24 | + @ApiProperty({ description: 'City name', example: 'New York' }) |
| 25 | + declare city: string; |
| 26 | + |
| 27 | + @ApiProperty({ description: 'ZIP code (US format)', example: '10001' }) |
| 28 | + declare zipCode: string; |
| 29 | + |
| 30 | + @ApiProperty({ |
| 31 | + description: 'Country code (ISO 3166-1 alpha-2)', |
| 32 | + example: 'US', |
| 33 | + minLength: 2, |
| 34 | + maxLength: 2, |
| 35 | + }) |
| 36 | + declare country: string; |
| 37 | +} |
| 38 | + |
| 39 | +/** |
| 40 | + * Zod schema for CreateUserDto with nested address |
| 41 | + */ |
| 42 | +export const createUserSchema = z.object({ |
7 | 43 | name: z.string().min(2, 'Name must be at least 2 characters'), |
8 | 44 | email: z.string().email('Invalid email format'), |
9 | 45 | age: z.number().int().min(0).max(150).optional(), |
| 46 | + address: addressSchema.optional(), |
10 | 47 | }); |
11 | 48 |
|
12 | 49 | /** |
13 | | - * DTO with Zod schema for user creation |
| 50 | + * DTO with Zod schema and Swagger decorators. |
| 51 | + * Uses `implements z.infer<typeof schema>` to ensure type safety |
| 52 | + * between the Zod schema and class properties. |
14 | 53 | */ |
15 | | -export class CreateUserDto { |
| 54 | +export class CreateUserDto implements z.infer<typeof createUserSchema> { |
16 | 55 | static schema = createUserSchema; |
17 | 56 |
|
18 | | - name: string; |
19 | | - email: string; |
20 | | - age?: number; |
| 57 | + @ApiProperty({ |
| 58 | + description: 'User name', |
| 59 | + example: 'John Doe', |
| 60 | + minLength: 2, |
| 61 | + }) |
| 62 | + declare name: string; |
| 63 | + |
| 64 | + @ApiProperty({ |
| 65 | + description: 'User email address', |
| 66 | + |
| 67 | + format: 'email', |
| 68 | + }) |
| 69 | + declare email: string; |
| 70 | + |
| 71 | + @ApiPropertyOptional({ |
| 72 | + description: 'User age', |
| 73 | + example: 30, |
| 74 | + minimum: 0, |
| 75 | + maximum: 150, |
| 76 | + }) |
| 77 | + declare age?: number; |
| 78 | + |
| 79 | + @ApiPropertyOptional({ |
| 80 | + description: 'User address', |
| 81 | + type: () => AddressDto, |
| 82 | + }) |
| 83 | + declare address?: AddressDto; |
21 | 84 | } |
22 | 85 |
|
23 | 86 | /** |
24 | 87 | * Zod schema for QueryDto |
25 | 88 | */ |
26 | | -const querySchema = z.object({ |
| 89 | +export const querySchema = z.object({ |
27 | 90 | limit: z.coerce.number().int().min(1).max(100).optional(), |
28 | 91 | offset: z.coerce.number().int().min(0).optional(), |
29 | 92 | }); |
30 | 93 |
|
31 | 94 | /** |
32 | 95 | * DTO with Zod schema for query parameters |
33 | 96 | */ |
34 | | -export class QueryDto { |
| 97 | +export class QueryDto implements z.infer<typeof querySchema> { |
35 | 98 | static schema = querySchema; |
36 | 99 |
|
37 | | - limit?: number; |
38 | | - offset?: number; |
| 100 | + @ApiPropertyOptional({ |
| 101 | + description: 'Number of items to return', |
| 102 | + example: 10, |
| 103 | + minimum: 1, |
| 104 | + maximum: 100, |
| 105 | + }) |
| 106 | + declare limit?: number; |
| 107 | + |
| 108 | + @ApiPropertyOptional({ |
| 109 | + description: 'Number of items to skip', |
| 110 | + example: 0, |
| 111 | + minimum: 0, |
| 112 | + }) |
| 113 | + declare offset?: number; |
39 | 114 | } |
0 commit comments