@voznov/zod-dto-nestjs 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -4
- package/dist/index.cjs +1186 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +1191 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -117,12 +117,102 @@ app.useGlobalPipes(
|
|
|
117
117
|
);
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
+
## Response validation — `@ZodSerialize` / `@ZodResponse`
|
|
121
|
+
|
|
122
|
+
Method decorators that parse the return value of a controller (or any class) method through a Zod schema. If the method returns something that doesn't match the schema, a `ZodDtoSerializationError` is thrown — caught at runtime *before* the value reaches the client, so server-side bugs are surfaced as 500s instead of leaking malformed payloads or extra fields.
|
|
123
|
+
|
|
124
|
+
- **`@ZodSerialize`** — runtime parsing only. Use on services, repositories, internal methods.
|
|
125
|
+
- **`@ZodResponse`** — `@ZodSerialize` + auto-emit `@ApiResponse` Swagger metadata (and register inner DTOs via `@ApiExtraModels`). Use on controller routes.
|
|
126
|
+
|
|
127
|
+
Both come in two overloads:
|
|
128
|
+
|
|
129
|
+
- **Strict** — schema passed explicitly. The method's return type is constrained at compile time to match the schema's output; `tsc` errors on mismatch.
|
|
130
|
+
- **Loose** — no schema. Resolves from `design:returntype` metadata at runtime (`: NoteDto` annotation suffices). No compile-time check; doesn't work on generic return types (`NoteDto[]`, `Promise<NoteDto>`, unions) since TypeScript erases generics in metadata — pass the schema explicitly in that case.
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
|
|
134
|
+
import { ZodResponse } from '@voznov/zod-dto-nestjs';
|
|
135
|
+
import { z } from 'zod';
|
|
136
|
+
|
|
137
|
+
@Controller('notes')
|
|
138
|
+
export class NotesController {
|
|
139
|
+
// Strict + auto-Swagger: tsc enforces the return type, spec gets `$ref` to NoteDto.
|
|
140
|
+
@Get(':id')
|
|
141
|
+
@ZodResponse(NoteDto)
|
|
142
|
+
findOne(@Param() p: NoteIdParam): NoteDto { /* ... */ }
|
|
143
|
+
|
|
144
|
+
// Async + array: tsc enforces `Promise<NoteDto[]>`. Generics erased in design:returntype,
|
|
145
|
+
// so the schema must be passed explicitly here.
|
|
146
|
+
@Get()
|
|
147
|
+
@ZodResponse(z.array(NoteDto))
|
|
148
|
+
async list(): Promise<NoteDto[]> { /* ... */ }
|
|
149
|
+
|
|
150
|
+
// Override status (default 200) + description for the OpenAPI operation.
|
|
151
|
+
@Post()
|
|
152
|
+
@ZodResponse(NoteDto, { status: 201, description: 'note created' })
|
|
153
|
+
create(@Body() body: CreateNoteDto): NoteDto { /* ... */ }
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Runtime-only sibling for layers below the controller — same overloads, no Swagger emission:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { ZodSerialize } from '@voznov/zod-dto-nestjs';
|
|
161
|
+
|
|
162
|
+
class NotesService {
|
|
163
|
+
// Throws ZodDtoSerializationError if the return shape doesn't match.
|
|
164
|
+
@ZodSerialize(NoteDto)
|
|
165
|
+
findOne(id: string): NoteDto { /* ... */ }
|
|
166
|
+
|
|
167
|
+
// Loose: schema resolved from `design:returntype` (NoteDto class). Won't work for `Promise<...>` / `NoteDto[]` — generic erased to `Promise` / `Array`. Use the strict overload for those.
|
|
168
|
+
@ZodSerialize()
|
|
169
|
+
default(): NoteDto { /* ... */ }
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Options
|
|
174
|
+
|
|
175
|
+
Both decorators accept the full `ToDtoOptions` bag (`preprocessors`, `observers`, `errorClass` — same semantics as [`toDto.with`](https://www.npmjs.com/package/@voznov/zod-dto), but applied to the method's *return* value instead of an input). The default `errorClass` is `ZodDtoSerializationError` (vs `ZodDtoValidationError` for `toDto`), so an exception filter can split client errors from server bugs (see below).
|
|
176
|
+
|
|
177
|
+
`@ZodResponse` extends the bag with two Swagger-only fields:
|
|
178
|
+
|
|
179
|
+
- `status: number` — HTTP status for the OpenAPI response object. Default `200`.
|
|
180
|
+
- `description: string` — description on the OpenAPI response object.
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
@ZodResponse(NoteDto, { status: 201, observers: [(note) => metrics.recordCreate(note)] })
|
|
184
|
+
async create(): Promise<NoteDto> { /* ... */ }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Differentiating client errors from server errors
|
|
188
|
+
|
|
189
|
+
`ZodDtoSerializationError extends ZodDtoValidationError`, so a single exception filter can split request-validation failures (client → 400) from response-validation failures (server → 500):
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
import { ZodDtoValidationError } from '@voznov/zod-dto';
|
|
193
|
+
import { ZodDtoSerializationError } from '@voznov/zod-dto-nestjs';
|
|
194
|
+
|
|
195
|
+
@Catch(ZodDtoValidationError)
|
|
196
|
+
export class ZodExceptionFilter implements ExceptionFilter {
|
|
197
|
+
catch(error: ZodDtoValidationError, host: ArgumentsHost) {
|
|
198
|
+
const isServerBug = error instanceof ZodDtoSerializationError;
|
|
199
|
+
const status = isServerBug ? 500 : 400;
|
|
200
|
+
// log, format, respond...
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
120
205
|
## API
|
|
121
206
|
|
|
122
|
-
| Export
|
|
123
|
-
|
|
|
124
|
-
| `ZodValidationPipe`
|
|
125
|
-
| `
|
|
207
|
+
| Export | Description |
|
|
208
|
+
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
209
|
+
| `ZodValidationPipe` | `PipeTransform` for `@Body()` / `@Param()` / `@Query()`. Accepts `{ createError?: (issues: string[]) => Error }`. |
|
|
210
|
+
| `ZodValidationPipeOptions` | Options type for `ZodValidationPipe`. |
|
|
211
|
+
| `ZodSerialize(schema?, options?)` | Method decorator: runtime-parse the return value through `schema` (or via `design:returntype` if omitted). Throws `ZodDtoSerializationError` on mismatch. |
|
|
212
|
+
| `ZodResponse(schema?, options?)` | `ZodSerialize` + auto-emits `@ApiResponse` Swagger metadata (and `@ApiExtraModels` for inner DTOs). |
|
|
213
|
+
| `ZodResponseOptions` | Options type for `ZodResponse` (`ToDtoOptions & { status?, description? }`). |
|
|
214
|
+
| `ZodDtoSerializationError` | Subclass of `ZodDtoValidationError` thrown by `@ZodSerialize` / `@ZodResponse` when a method returns an invalid shape. |
|
|
215
|
+
| `applySwaggerDecorators(schema)` | Low-level: apply `@ApiProperty` metadata to a schema. Auto-invoked via `registerOnCreate`; export is for manual/edge-case use. |
|
|
126
216
|
|
|
127
217
|
## License
|
|
128
218
|
|