klasik 2.2.0 → 2.4.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.
@@ -1,350 +0,0 @@
1
- # Request and Response Validation Guide
2
-
3
- ## Overview
4
-
5
- Klasik provides automatic runtime validation of both API requests and responses using class-validator. This ensures that:
6
- - **Requests**: Data sent to APIs is valid before transmission
7
- - **Responses**: Data received from APIs matches the expected schema
8
-
9
- ## How It Works
10
-
11
- ### Response Validation
12
- 1. **Generation**: When using `--class-validator` flag, Klasik generates validation decorators
13
- 2. **Transformation**: Responses are transformed to class instances using class-transformer
14
- 3. **Validation**: Instances are validated using class-validator's `validate()` function
15
- 4. **Error Handling**: Validation failures throw errors or invoke custom callbacks
16
-
17
- ### Request Validation
18
- 1. **Instance Check**: Verify request body is an instance of the expected class
19
- 2. **Validation**: Validate the instance using class-validator's `validate()` function
20
- 3. **Error Handling**: Failures throw errors or invoke custom callbacks
21
- 4. **Transmission**: Only valid requests are sent to the server
22
-
23
- ## Configuration Options
24
-
25
- ### Request Validation
26
-
27
- #### `enableRequestValidation`
28
-
29
- - **Type**: `boolean`
30
- - **Default**: `false`
31
- - **Description**: Enable automatic validation of API request bodies
32
-
33
- #### `onRequestValidationError`
34
-
35
- - **Type**: `(errors: any[], modelClass: any, instance: any) => void`
36
- - **Default**: `undefined`
37
- - **Description**: Custom callback for request validation errors
38
-
39
- ### Response Validation
40
-
41
- #### `enableResponseValidation`
42
-
43
- - **Type**: `boolean`
44
- - **Default**: `false`
45
- - **Description**: Enable automatic validation of API responses
46
-
47
- #### `onResponseValidationError`
48
-
49
- - **Type**: `(errors: ValidationError[], modelClass: any, instance: any) => void`
50
- - **Default**: `undefined`
51
- - **Description**: Custom callback for response validation errors
52
-
53
- ## Generated Decorators
54
-
55
- When `--class-validator` is enabled, Klasik generates:
56
-
57
- ### Type Validators
58
- - `@IsString()` - String properties
59
- - `@IsNumber()` - Numeric properties
60
- - `@IsBoolean()` - Boolean properties
61
- - `@IsArray()` - Array properties
62
- - `@ValidateNested()` - Nested objects
63
-
64
- ### Format Validators
65
- - `@IsEmail()` - Email format
66
- - `@IsUrl()` - URL format
67
- - `@IsUUID()` - UUID format
68
- - `@IsDate()` - Date/datetime format
69
-
70
- ### Constraint Validators
71
- - `@Min(n)` / `@Max(n)` - Numeric ranges
72
- - `@MinLength(n)` / `@MaxLength(n)` - String length
73
- - `@Matches(pattern)` - Regex patterns
74
- - `@ArrayMinSize(n)` / `@ArrayMaxSize(n)` - Array size
75
- - `@ArrayUnique()` - Unique array items
76
-
77
- ### Optional Properties
78
- - `@IsOptional()` - For optional/nullable properties
79
-
80
- ## Usage Examples
81
-
82
- ### Basic Usage
83
-
84
- ```typescript
85
- const config = new Configuration({
86
- basePath: 'https://api.example.com',
87
- enableRequestValidation: true,
88
- enableResponseValidation: true
89
- });
90
-
91
- const api = new UsersApi(config);
92
-
93
- // Create and validate request
94
- const newUser = new CreateUserRequest();
95
- newUser.name = 'John Doe';
96
- newUser.email = 'john@example.com';
97
-
98
- // Validates request before sending, validates response after receiving
99
- const user = await api.createUser(newUser);
100
- ```
101
-
102
- ### Request Validation Only
103
-
104
- ```typescript
105
- const config = new Configuration({
106
- enableRequestValidation: true // Only validate outgoing requests
107
- });
108
-
109
- const api = new UsersApi(config);
110
-
111
- // Must use class instances
112
- const newUser = new CreateUserRequest();
113
- newUser.name = 'John Doe';
114
- await api.createUser(newUser); // Validated before sending
115
- ```
116
-
117
- ### Response Validation Only
118
-
119
- ```typescript
120
- const config = new Configuration({
121
- enableResponseValidation: true // Only validate incoming responses
122
- });
123
-
124
- const api = new UsersApi(config);
125
- const users = await api.listUsers(); // Response validated
126
- ```
127
-
128
- ### With Error Callbacks
129
-
130
- ```typescript
131
- const config = new Configuration({
132
- enableRequestValidation: true,
133
- onRequestValidationError: (errors, modelClass, instance) => {
134
- logger.error(`Request validation failed for ${modelClass.name}`, { errors });
135
- },
136
- enableResponseValidation: true,
137
- onResponseValidationError: (errors, modelClass, instance) => {
138
- logger.error(`Response validation failed for ${modelClass.name}`, { errors });
139
- }
140
- });
141
- ```
142
-
143
- ### Handling Validation Errors
144
-
145
- ```typescript
146
- import { ValidationError, RequestNotInstanceError } from './generated/runtime/response-transformer';
147
-
148
- try {
149
- const newUser = new CreateUserRequest();
150
- newUser.name = ''; // Invalid
151
- await api.createUser(newUser);
152
- } catch (error) {
153
- if (error instanceof RequestNotInstanceError) {
154
- console.error('Request must be a class instance');
155
- } else if (error instanceof ValidationError) {
156
- console.error(`Validation failed for ${error.modelClass.name}`);
157
- error.validationErrors.forEach(err => {
158
- console.error(` ${err.property}:`, err.constraints);
159
- });
160
- }
161
- }
162
- ```
163
-
164
- ## Best Practices
165
-
166
- 1. **Enable During Development**: Use validation in development to catch API contract changes
167
- 2. **Custom Callbacks in Production**: Log validation errors to monitoring services
168
- 3. **Graceful Degradation**: Use callbacks to handle errors without blocking user flow
169
- 4. **Generate with --class-validator**: Always use this flag for validation support
170
- 5. **Use Class Instances**: Always instantiate request classes (e.g., `new CreateUserRequest()`)
171
- 6. **Validate Both Directions**: Enable both request and response validation for maximum safety
172
-
173
- ## Performance Considerations
174
-
175
- - Both validations are async
176
- - Request validation runs before sending (adds latency before transmission)
177
- - Response validation runs after transformation
178
- - Array validation runs in parallel for better performance
179
- - Both are opt-in (disabled by default) for minimal overhead
180
- - Gracefully skips if models lack validation decorators
181
-
182
- ## Troubleshooting
183
-
184
- ### Request Validation not running
185
-
186
- Check that:
187
- 1. Models generated with `--class-validator` flag
188
- 2. `enableRequestValidation: true` in Configuration
189
- 3. Request body is a class instance (not plain object)
190
- 4. `class-validator` package is installed
191
-
192
- ### Response Validation not running
193
-
194
- Check that:
195
- 1. Models generated with `--class-validator` flag
196
- 2. `enableResponseValidation: true` in Configuration
197
- 3. `enableResponseTransformation` is not disabled
198
- 4. `class-validator` package is installed
199
-
200
- ### "Request must be an instance" errors
201
-
202
- - Use `new ModelClass()` instead of plain objects: `{ field: 'value' }`
203
- - Transform plain objects first: `plainToInstance(ModelClass, plainObject)`
204
-
205
- ### Validation always passes
206
-
207
- - Verify decorators are present in generated models
208
- - Check that constraints match your API schema
209
- - Ensure nested objects have `@ValidateNested()` decorator
210
-
211
- ## CLI Usage
212
-
213
- Generate models with validation decorators:
214
-
215
- ```bash
216
- klasik generate \
217
- --url https://api.example.com/openapi.json \
218
- --output ./src/generated \
219
- --class-validator
220
- ```
221
-
222
- Then use in your code:
223
-
224
- ```typescript
225
- import { Configuration, TasksApi, NewTask } from './generated';
226
-
227
- const config = new Configuration({
228
- basePath: 'https://api.example.com',
229
- enableRequestValidation: true,
230
- enableResponseValidation: true
231
- });
232
-
233
- const api = new TasksApi(config);
234
-
235
- // Request will be validated
236
- const newTask = new NewTask();
237
- newTask.title = 'My Task';
238
- const created = await api.createTask(newTask);
239
-
240
- // Response will be validated
241
- const tasks = await api.listTasks();
242
- ```
243
-
244
- ## Examples
245
-
246
- ### Validation in NestJS
247
-
248
- ```typescript
249
- import { Injectable } from '@nestjs/common';
250
- import { Configuration, UsersApi } from './generated';
251
-
252
- @Injectable()
253
- export class UserService {
254
- private api: UsersApi;
255
-
256
- constructor() {
257
- const config = new Configuration({
258
- basePath: process.env.API_BASE_URL,
259
- enableRequestValidation: true,
260
- enableResponseValidation: true,
261
- onRequestValidationError: (errors, modelClass, instance) => {
262
- this.logger.error('Request validation failed', { errors });
263
- },
264
- onResponseValidationError: (errors, modelClass, instance) => {
265
- this.logger.error('Response validation failed', { errors });
266
- }
267
- });
268
-
269
- this.api = new UsersApi(config);
270
- }
271
-
272
- async createUser(userData: CreateUserDto) {
273
- const newUser = new CreateUserRequest();
274
- Object.assign(newUser, userData);
275
-
276
- return await this.api.createUser(newUser);
277
- }
278
- }
279
- ```
280
-
281
- ### Validation with Monitoring
282
-
283
- ```typescript
284
- import * as Sentry from '@sentry/node';
285
-
286
- const config = new Configuration({
287
- basePath: 'https://api.example.com',
288
- enableRequestValidation: true,
289
- enableResponseValidation: true,
290
- onRequestValidationError: (errors, modelClass, instance) => {
291
- Sentry.captureException(new Error('Request validation failed'), {
292
- extra: {
293
- modelClass: modelClass.name,
294
- errors: errors.map(e => e.toString()),
295
- instance
296
- }
297
- });
298
- },
299
- onResponseValidationError: (errors, modelClass, instance) => {
300
- Sentry.captureException(new Error('Response validation failed'), {
301
- extra: {
302
- modelClass: modelClass.name,
303
- errors: errors.map(e => e.property),
304
- instance
305
- }
306
- });
307
- }
308
- });
309
- ```
310
-
311
- ## Advanced Configuration
312
-
313
- ### Selective Validation
314
-
315
- You can enable validation per-request by cloning the configuration:
316
-
317
- ```typescript
318
- const baseConfig = new Configuration({
319
- basePath: 'https://api.example.com',
320
- enableRequestValidation: false,
321
- enableResponseValidation: false
322
- });
323
-
324
- // Enable for specific request
325
- const validatedConfig = baseConfig.clone({
326
- enableRequestValidation: true,
327
- enableResponseValidation: true
328
- });
329
-
330
- const api = new UsersApi(validatedConfig);
331
- await api.createUser(newUser); // This request is validated
332
- ```
333
-
334
- ### Environment-Based Configuration
335
-
336
- ```typescript
337
- const config = new Configuration({
338
- basePath: process.env.API_BASE_URL,
339
- // Enable in development, disable in production
340
- enableRequestValidation: process.env.NODE_ENV === 'development',
341
- enableResponseValidation: process.env.NODE_ENV === 'development',
342
- // Always log errors
343
- onRequestValidationError: (errors, modelClass) => {
344
- console.error(`Request validation failed for ${modelClass.name}`, errors);
345
- },
346
- onResponseValidationError: (errors, modelClass) => {
347
- console.error(`Response validation failed for ${modelClass.name}`, errors);
348
- }
349
- });
350
- ```
Binary file