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.
- package/README.md +49 -0
- package/dist/bin/go-schema-gen +0 -0
- package/dist/cli/commands/generate-crd.d.ts +1 -0
- package/dist/cli/commands/generate-crd.d.ts.map +1 -1
- package/dist/cli/commands/generate-crd.js +17 -1
- package/dist/cli/commands/generate-crd.js.map +1 -1
- package/dist/cli/utils/options.d.ts +8 -0
- package/dist/cli/utils/options.d.ts.map +1 -1
- package/dist/cli/utils/options.js +20 -0
- package/dist/cli/utils/options.js.map +1 -1
- package/dist/ir/ir-filter.d.ts +52 -0
- package/dist/ir/ir-filter.d.ts.map +1 -0
- package/dist/ir/ir-filter.js +129 -0
- package/dist/ir/ir-filter.js.map +1 -0
- package/dist/plugins/class-validator-plugin.d.ts.map +1 -1
- package/dist/plugins/class-validator-plugin.js +23 -7
- package/dist/plugins/class-validator-plugin.js.map +1 -1
- package/package.json +7 -4
- package/demo-output/models/index.ts +0 -2
- package/demo-output/models/owner.ts +0 -74
- package/demo-output/models/pet.ts +0 -107
- package/demo-output/package.json +0 -14
- package/demo-output/tsconfig.json +0 -26
- package/dist/__tests__/test-helpers/cleanup-utils.d.ts +0 -64
- package/dist/__tests__/test-helpers/cleanup-utils.d.ts.map +0 -1
- package/dist/__tests__/test-helpers/cleanup-utils.js +0 -236
- package/dist/__tests__/test-helpers/cleanup-utils.js.map +0 -1
- package/docs/ARCHITECTURE.md +0 -845
- package/docs/JSDOC_ESCAPING.md +0 -280
- package/docs/json-schema-support.md +0 -353
- package/docs/validation.md +0 -350
- package/tools/go-schema-gen/go-schema-gen +0 -0
package/docs/validation.md
DELETED
|
@@ -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
|