ts-class-to-openapi 1.0.4 → 1.0.6
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 +369 -875
- package/dist/__test__/entities/additional-test-classes.d.ts +12 -0
- package/dist/__test__/entities/decorated-classes.d.ts +54 -0
- package/dist/__test__/entities/nested-classes.d.ts +70 -0
- package/dist/__test__/entities/pure-classes.d.ts +37 -0
- package/dist/__test__/entities/schema-validation-classes.d.ts +35 -0
- package/dist/__test__/index.d.ts +3 -6
- package/dist/__test__/test.d.ts +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +476 -1075
- package/dist/index.js +476 -1075
- package/dist/run.d.ts +1 -1
- package/dist/run.js +1064 -1101
- package/dist/transformer.d.ts +1 -471
- package/dist/transformer.fixtures.d.ts +21 -0
- package/dist/types.d.ts +55 -6
- package/package.json +16 -15
- package/dist/__test__/entities/address.entity.d.ts +0 -5
- package/dist/__test__/entities/array.entity.d.ts +0 -7
- package/dist/__test__/entities/broken.entity.d.ts +0 -7
- package/dist/__test__/entities/complete.entity.d.ts +0 -16
- package/dist/__test__/entities/complex-generics.entity.d.ts +0 -33
- package/dist/__test__/entities/comprehensive-enum.entity.d.ts +0 -23
- package/dist/__test__/entities/enum.entity.d.ts +0 -29
- package/dist/__test__/entities/generic.entity.d.ts +0 -11
- package/dist/__test__/entities/optional-properties.entity.d.ts +0 -11
- package/dist/__test__/entities/plain.entity.d.ts +0 -19
- package/dist/__test__/entities/simple.entity.d.ts +0 -5
- package/dist/__test__/entities/upload.entity.d.ts +0 -8
- package/dist/__test__/entities/user-role-generic.entity.d.ts +0 -13
- package/dist/__test__/test-entities/duplicate-name.entity.d.ts +0 -5
- package/dist/__test__/test-entities/generic.entity.d.ts +0 -11
- /package/dist/__test__/{enum.test.d.ts → testCases/debug.test.d.ts} +0 -0
- /package/dist/__test__/{generic-types.test.d.ts → testCases/decorated-classes.test.d.ts} +0 -0
- /package/dist/__test__/{integration.test.d.ts → testCases/edge-cases.test.d.ts} +0 -0
- /package/dist/__test__/{main.test.d.ts → testCases/nested-classes.test.d.ts} +0 -0
- /package/dist/__test__/{optional-properties.test.d.ts → testCases/pure-classes.test.d.ts} +0 -0
- /package/dist/__test__/{plain.test.d.ts → testCases/schema-validation.test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,51 +1,34 @@
|
|
|
1
1
|
# 🔄 ts-class-to-openapi
|
|
2
2
|
|
|
3
|
-
✨ **Transform TypeScript classes into OpenAPI 3.1.0
|
|
3
|
+
✨ **Transform TypeScript classes into OpenAPI 3.1.0 schemas**
|
|
4
4
|
|
|
5
|
-
A
|
|
5
|
+
A robust and efficient library that automatically transforms TypeScript classes into OpenAPI-compatible schemas. Compatible with **pure TypeScript classes** and **class-validator decorated classes**.
|
|
6
6
|
|
|
7
|
-
>
|
|
8
|
-
>
|
|
9
|
-
> - **Pure TypeScript classes** without requiring any decorators or external dependencies!
|
|
10
|
-
> - **Full enum support** with `@IsEnum` decorator for string, numeric, and object enums
|
|
11
|
-
> - Perfect for transforming existing codebases instantly.
|
|
7
|
+
> **What is OpenAPI?** OpenAPI (formerly Swagger) is the industry standard for describing REST APIs. This library generates OpenAPI 3.1.0 compatible schemas that can be used for API documentation, client SDK generation, and validation.
|
|
12
8
|
|
|
13
9
|
## 🚀 Key Features
|
|
14
10
|
|
|
15
|
-
- ✅ **
|
|
16
|
-
- ✅ **
|
|
17
|
-
- ✅ **
|
|
18
|
-
- ✅ **
|
|
19
|
-
- ✅ **
|
|
20
|
-
- ✅ **OpenAPI 3.1.0** - Industry-standard schema generation
|
|
21
|
-
- ✅ **TypeScript Native** - Full type support and safety
|
|
22
|
-
- ✅ **High Performance** - Singleton pattern with built-in caching
|
|
23
|
-
- ✅ **Nested Objects** - Handles complex relationships automatically
|
|
24
|
-
- ✅ **Typed Arrays** - Full support for arrays with validation
|
|
25
|
-
- ✅ **File Uploads** - Binary file upload support
|
|
11
|
+
- ✅ **Direct transformation** - Convert any TypeScript class without additional configuration
|
|
12
|
+
- ✅ **Zero runtime dependencies** - No `reflect-metadata` or complex configurations required
|
|
13
|
+
- ✅ **class-validator integration** - Enrich schemas using validation decorators
|
|
14
|
+
- ✅ **Automatic documentation generation** - Generate Swagger documentation from existing classes
|
|
15
|
+
- ✅ **Native TypeScript support** - Full compatibility with enums, arrays, and nested objects
|
|
26
16
|
|
|
27
|
-
## 🎯
|
|
17
|
+
## 🎯 Quick Example
|
|
28
18
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- 🌐 **REST APIs**: Generate Swagger documentation from your existing TypeScript classes
|
|
32
|
-
- 📚 **Auto Documentation**: Maintain consistency between TypeScript types and API contracts
|
|
33
|
-
- 🧪 **API Testing**: Create mock data structures for testing
|
|
34
|
-
- 🔧 **Microservices**: Ensure schema consistency across services
|
|
35
|
-
- ⚡ **Legacy Projects**: Works without enabling `emitDecoratorMetadata`
|
|
36
|
-
- 🎯 **Pure TypeScript**: Transform classes without any decorators
|
|
37
|
-
- 🔍 **Enhanced Validation**: Add class-validator decorators for richer schemas
|
|
38
|
-
|
|
39
|
-
### 📋 About OpenAPI
|
|
40
|
-
|
|
41
|
-
**OpenAPI** (formerly Swagger) is the industry standard specification for describing REST APIs in a structured, machine-readable format. This library generates **OpenAPI 3.1.0** compatible schemas from your TypeScript classes.
|
|
19
|
+
```typescript
|
|
20
|
+
import { transform } from 'ts-class-to-openapi'
|
|
42
21
|
|
|
43
|
-
|
|
22
|
+
class User {
|
|
23
|
+
id: number
|
|
24
|
+
name: string
|
|
25
|
+
email: string
|
|
26
|
+
age?: number
|
|
27
|
+
}
|
|
44
28
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- Consistency across your API ecosystem
|
|
29
|
+
const schema = transform(User)
|
|
30
|
+
// Returns complete OpenAPI schema ready for Swagger/API documentation
|
|
31
|
+
```
|
|
49
32
|
|
|
50
33
|
## 📦 Installation
|
|
51
34
|
|
|
@@ -60,67 +43,77 @@ yarn add ts-class-to-openapi
|
|
|
60
43
|
pnpm add ts-class-to-openapi
|
|
61
44
|
```
|
|
62
45
|
|
|
63
|
-
###
|
|
46
|
+
### Additional Dependencies for class-validator
|
|
64
47
|
|
|
65
|
-
|
|
48
|
+
To use validation decorators and generate more detailed schemas:
|
|
66
49
|
|
|
67
50
|
```bash
|
|
68
|
-
# Using npm
|
|
69
51
|
npm install ts-class-to-openapi class-validator
|
|
70
|
-
|
|
71
|
-
# Using yarn
|
|
72
|
-
yarn add ts-class-to-openapi class-validator
|
|
73
|
-
|
|
74
|
-
# Using pnpm
|
|
75
|
-
pnpm add ts-class-to-openapi class-validator
|
|
76
52
|
```
|
|
77
53
|
|
|
78
|
-
> **Note**: `class-validator` is only required
|
|
54
|
+
> **Note**: The `class-validator` dependency is optional and only required when using validation decorators.
|
|
79
55
|
|
|
80
|
-
##
|
|
56
|
+
## 🎨 Class Transformation Examples
|
|
81
57
|
|
|
82
|
-
|
|
58
|
+
### 1. Basic TypeScript Class
|
|
83
59
|
|
|
84
|
-
|
|
60
|
+
Fundamental method: transform any TypeScript class without decorators:
|
|
85
61
|
|
|
86
62
|
```typescript
|
|
87
|
-
// ESM import
|
|
88
63
|
import { transform } from 'ts-class-to-openapi'
|
|
89
|
-
import { IsString, IsEmail, IsNotEmpty, IsEnum } from 'class-validator'
|
|
90
|
-
|
|
91
|
-
enum UserType {
|
|
92
|
-
ADMIN = 'admin',
|
|
93
|
-
USER = 'user',
|
|
94
|
-
}
|
|
95
64
|
|
|
65
|
+
// Basic TypeScript class - no decorators required
|
|
96
66
|
class User {
|
|
97
|
-
|
|
98
|
-
@IsNotEmpty()
|
|
67
|
+
id: number
|
|
99
68
|
name: string
|
|
100
|
-
|
|
101
|
-
@IsEmail()
|
|
102
69
|
email: string
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
70
|
+
age: number
|
|
71
|
+
active: boolean
|
|
72
|
+
tags: string[]
|
|
73
|
+
createdAt: Date
|
|
106
74
|
}
|
|
107
75
|
|
|
108
|
-
|
|
109
|
-
|
|
76
|
+
// Transform class to OpenAPI schema
|
|
77
|
+
const result = transform(User)
|
|
78
|
+
console.log(JSON.stringify(result, null, 2))
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Generated output:**
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"name": "User",
|
|
86
|
+
"schema": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"properties": {
|
|
89
|
+
"id": { "type": "number" },
|
|
90
|
+
"name": { "type": "string" },
|
|
91
|
+
"email": { "type": "string" },
|
|
92
|
+
"age": { "type": "number" },
|
|
93
|
+
"active": { "type": "boolean" },
|
|
94
|
+
"tags": {
|
|
95
|
+
"type": "array",
|
|
96
|
+
"items": { "type": "string" }
|
|
97
|
+
},
|
|
98
|
+
"createdAt": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"format": "date-time"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"required": ["id", "name", "email", "age", "active", "tags", "createdAt"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
110
106
|
```
|
|
111
107
|
|
|
112
|
-
###
|
|
108
|
+
### 2. Class with Advanced Validations
|
|
109
|
+
|
|
110
|
+
For more detailed schemas, class-validator decorators can be incorporated:
|
|
113
111
|
|
|
114
112
|
```typescript
|
|
115
|
-
// TypeScript with CommonJS configuration
|
|
116
113
|
import { transform } from 'ts-class-to-openapi'
|
|
117
|
-
import { IsString, IsEmail, IsNotEmpty,
|
|
118
|
-
|
|
119
|
-
enum UserType {
|
|
120
|
-
ADMIN = 'admin',
|
|
121
|
-
USER = 'user',
|
|
122
|
-
}
|
|
114
|
+
import { IsString, IsEmail, IsNotEmpty, IsInt, Min, Max } from 'class-validator'
|
|
123
115
|
|
|
116
|
+
// Class with validation decorators
|
|
124
117
|
class User {
|
|
125
118
|
@IsString()
|
|
126
119
|
@IsNotEmpty()
|
|
@@ -129,79 +122,125 @@ class User {
|
|
|
129
122
|
@IsEmail()
|
|
130
123
|
email: string
|
|
131
124
|
|
|
132
|
-
@
|
|
133
|
-
|
|
125
|
+
@IsInt()
|
|
126
|
+
@Min(18)
|
|
127
|
+
@Max(100)
|
|
128
|
+
age: number
|
|
134
129
|
}
|
|
135
130
|
|
|
136
|
-
const
|
|
137
|
-
console.log(JSON.stringify(schema, null, 2))
|
|
131
|
+
const result = transform(User)
|
|
138
132
|
```
|
|
139
133
|
|
|
140
|
-
|
|
134
|
+
**Generated output:**
|
|
141
135
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
{
|
|
146
|
-
"
|
|
147
|
-
|
|
148
|
-
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"name": "User",
|
|
139
|
+
"schema": {
|
|
140
|
+
"type": "object",
|
|
141
|
+
"properties": {
|
|
142
|
+
"name": { "type": "string" },
|
|
143
|
+
"email": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"format": "email"
|
|
146
|
+
},
|
|
147
|
+
"age": {
|
|
148
|
+
"type": "integer",
|
|
149
|
+
"format": "int32",
|
|
150
|
+
"minimum": 18,
|
|
151
|
+
"maximum": 100
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"required": ["name", "email", "age"]
|
|
149
155
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
> **Note**: The `experimentalDecorators` option is only required if you plan to use class-validator decorators. Pure TypeScript classes work without any special configuration.
|
|
153
|
-
|
|
154
|
-
## 🎨 Two Transformation Modes
|
|
156
|
+
}
|
|
157
|
+
```
|
|
155
158
|
|
|
156
|
-
###
|
|
159
|
+
### 3. Nested Objects and Arrays
|
|
157
160
|
|
|
158
|
-
|
|
161
|
+
Automatic processing of complex relationships:
|
|
159
162
|
|
|
160
163
|
```typescript
|
|
161
164
|
import { transform } from 'ts-class-to-openapi'
|
|
162
165
|
|
|
163
|
-
|
|
164
|
-
|
|
166
|
+
class Address {
|
|
167
|
+
street: string
|
|
168
|
+
city: string
|
|
169
|
+
zipCode: string
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
class Role {
|
|
165
173
|
id: number
|
|
166
174
|
name: string
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
175
|
+
permissions: string[]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
class User {
|
|
179
|
+
id: number
|
|
180
|
+
name: string
|
|
181
|
+
email: string
|
|
182
|
+
address: Address // Nested object
|
|
183
|
+
roles: Role[] // Array of objects
|
|
184
|
+
phone?: string // Optional property
|
|
172
185
|
}
|
|
173
186
|
|
|
174
|
-
const schema = transform(
|
|
187
|
+
const schema = transform(User)
|
|
175
188
|
```
|
|
176
189
|
|
|
177
|
-
**
|
|
190
|
+
**Generated output:**
|
|
178
191
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"name": "User",
|
|
195
|
+
"schema": {
|
|
196
|
+
"type": "object",
|
|
197
|
+
"properties": {
|
|
198
|
+
"id": { "type": "number" },
|
|
199
|
+
"name": { "type": "string" },
|
|
200
|
+
"email": { "type": "string" },
|
|
201
|
+
"address": {
|
|
202
|
+
"type": "object",
|
|
203
|
+
"properties": {
|
|
204
|
+
"street": { "type": "string" },
|
|
205
|
+
"city": { "type": "string" },
|
|
206
|
+
"zipCode": { "type": "string" }
|
|
207
|
+
},
|
|
208
|
+
"required": ["street", "city", "zipCode"]
|
|
209
|
+
},
|
|
210
|
+
"roles": {
|
|
211
|
+
"type": "array",
|
|
212
|
+
"items": {
|
|
213
|
+
"type": "object",
|
|
214
|
+
"properties": {
|
|
215
|
+
"id": { "type": "number" },
|
|
216
|
+
"name": { "type": "string" },
|
|
217
|
+
"permissions": {
|
|
218
|
+
"type": "array",
|
|
219
|
+
"items": { "type": "string" }
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
"required": ["id", "name", "permissions"]
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
"phone": { "type": "string" }
|
|
226
|
+
},
|
|
227
|
+
"required": ["id", "name", "email", "address", "roles"]
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
184
231
|
|
|
185
|
-
###
|
|
232
|
+
### 4. Enumerations and Special Types
|
|
186
233
|
|
|
187
|
-
|
|
234
|
+
Full compatibility with TypeScript enumerations:
|
|
188
235
|
|
|
189
236
|
```typescript
|
|
190
237
|
import { transform } from 'ts-class-to-openapi'
|
|
191
|
-
import {
|
|
192
|
-
IsString,
|
|
193
|
-
IsNumber,
|
|
194
|
-
IsPositive,
|
|
195
|
-
IsArray,
|
|
196
|
-
IsNotEmpty,
|
|
197
|
-
IsEnum,
|
|
198
|
-
} from 'class-validator'
|
|
238
|
+
import { IsEnum } from 'class-validator'
|
|
199
239
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
ARCHIVED = 'archived',
|
|
240
|
+
enum UserType {
|
|
241
|
+
ADMIN = 'admin',
|
|
242
|
+
USER = 'user',
|
|
243
|
+
MODERATOR = 'moderator',
|
|
205
244
|
}
|
|
206
245
|
|
|
207
246
|
enum Priority {
|
|
@@ -210,164 +249,105 @@ enum Priority {
|
|
|
210
249
|
HIGH = 3,
|
|
211
250
|
}
|
|
212
251
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
@IsPositive()
|
|
217
|
-
id: number
|
|
218
|
-
|
|
219
|
-
@IsString()
|
|
220
|
-
@IsNotEmpty()
|
|
221
|
-
name: string
|
|
222
|
-
|
|
223
|
-
@IsNumber()
|
|
224
|
-
@IsPositive()
|
|
225
|
-
price: number
|
|
226
|
-
|
|
227
|
-
@IsEnum(ProductStatus)
|
|
228
|
-
@IsNotEmpty()
|
|
229
|
-
status: ProductStatus
|
|
252
|
+
class Task {
|
|
253
|
+
@IsEnum(UserType)
|
|
254
|
+
assignedTo: UserType
|
|
230
255
|
|
|
231
256
|
@IsEnum(Priority)
|
|
232
257
|
priority?: Priority
|
|
233
258
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const schema = transform(Product)
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
**Benefits:**
|
|
242
|
-
|
|
243
|
-
- ✅ Rich validation constraints
|
|
244
|
-
- ✅ Required field specification
|
|
245
|
-
- ✅ Format validation (email, date, etc.)
|
|
246
|
-
- ✅ String length constraints
|
|
247
|
-
- ✅ Number range validation
|
|
248
|
-
- ✅ Array size validation
|
|
249
|
-
- ✅ Enum value constraints with automatic type detection
|
|
250
|
-
|
|
251
|
-
## 🚀 Quick Start
|
|
252
|
-
|
|
253
|
-
### Pure TypeScript Classes
|
|
254
|
-
|
|
255
|
-
Transform any TypeScript class without requiring decorators:
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
import { transform } from 'ts-class-to-openapi'
|
|
259
|
-
|
|
260
|
-
// Pure TypeScript class - no decorators needed!
|
|
261
|
-
class User {
|
|
262
|
-
id: number
|
|
263
|
-
name: string
|
|
264
|
-
email: string
|
|
265
|
-
age: number
|
|
266
|
-
isActive: boolean
|
|
267
|
-
tags: string[]
|
|
268
|
-
createdAt: Date
|
|
259
|
+
title: string
|
|
260
|
+
completed: boolean
|
|
261
|
+
dueDate: Date
|
|
269
262
|
}
|
|
270
263
|
|
|
271
|
-
|
|
272
|
-
const result = transform(User)
|
|
273
|
-
console.log(JSON.stringify(result, null, 2))
|
|
264
|
+
const schema = transform(Task)
|
|
274
265
|
```
|
|
275
266
|
|
|
276
|
-
**Generated
|
|
267
|
+
**Generated output:**
|
|
277
268
|
|
|
278
269
|
```json
|
|
279
270
|
{
|
|
280
|
-
"name": "
|
|
271
|
+
"name": "Task",
|
|
281
272
|
"schema": {
|
|
282
273
|
"type": "object",
|
|
283
274
|
"properties": {
|
|
284
|
-
"
|
|
285
|
-
"type": "
|
|
286
|
-
|
|
287
|
-
"name": {
|
|
288
|
-
"type": "string"
|
|
289
|
-
},
|
|
290
|
-
"email": {
|
|
291
|
-
"type": "string"
|
|
292
|
-
},
|
|
293
|
-
"age": {
|
|
294
|
-
"type": "number"
|
|
295
|
-
},
|
|
296
|
-
"isActive": {
|
|
297
|
-
"type": "boolean"
|
|
275
|
+
"assignedTo": {
|
|
276
|
+
"type": "string",
|
|
277
|
+
"enum": ["admin", "user", "moderator"]
|
|
298
278
|
},
|
|
299
|
-
"
|
|
300
|
-
"type": "
|
|
301
|
-
"
|
|
302
|
-
"type": "string"
|
|
303
|
-
}
|
|
279
|
+
"priority": {
|
|
280
|
+
"type": "number",
|
|
281
|
+
"enum": [1, 2, 3]
|
|
304
282
|
},
|
|
305
|
-
"
|
|
283
|
+
"title": { "type": "string" },
|
|
284
|
+
"completed": { "type": "boolean" },
|
|
285
|
+
"dueDate": {
|
|
306
286
|
"type": "string",
|
|
307
287
|
"format": "date-time"
|
|
308
288
|
}
|
|
309
289
|
},
|
|
310
|
-
"required": ["
|
|
290
|
+
"required": ["assignedTo", "title", "completed", "dueDate"]
|
|
311
291
|
}
|
|
312
292
|
}
|
|
313
293
|
```
|
|
314
294
|
|
|
315
|
-
###
|
|
295
|
+
### 5. File Upload
|
|
316
296
|
|
|
317
|
-
|
|
297
|
+
Integrated support for binary file handling:
|
|
318
298
|
|
|
319
299
|
```typescript
|
|
320
300
|
import { transform } from 'ts-class-to-openapi'
|
|
321
|
-
import {
|
|
301
|
+
import { IsNotEmpty, IsOptional } from 'class-validator'
|
|
322
302
|
|
|
323
|
-
//
|
|
324
|
-
class
|
|
325
|
-
|
|
303
|
+
// Custom file type definition
|
|
304
|
+
class UploadFile {}
|
|
305
|
+
|
|
306
|
+
class UserProfile {
|
|
326
307
|
@IsNotEmpty()
|
|
327
|
-
|
|
308
|
+
profilePicture: UploadFile
|
|
328
309
|
|
|
329
|
-
@
|
|
330
|
-
|
|
310
|
+
@IsOptional()
|
|
311
|
+
resume: UploadFile
|
|
331
312
|
|
|
332
|
-
|
|
333
|
-
@Min(18)
|
|
334
|
-
@Max(100)
|
|
335
|
-
age: number
|
|
313
|
+
documents: UploadFile[] // Multiple files
|
|
336
314
|
}
|
|
337
315
|
|
|
338
|
-
|
|
339
|
-
const result = transform(User)
|
|
340
|
-
console.log(JSON.stringify(result, null, 2))
|
|
316
|
+
const schema = transform(UserProfile)
|
|
341
317
|
```
|
|
342
318
|
|
|
343
|
-
**Generated
|
|
319
|
+
**Generated output:**
|
|
344
320
|
|
|
345
321
|
```json
|
|
346
322
|
{
|
|
347
|
-
"name": "
|
|
323
|
+
"name": "UserProfile",
|
|
348
324
|
"schema": {
|
|
349
325
|
"type": "object",
|
|
350
326
|
"properties": {
|
|
351
|
-
"
|
|
352
|
-
"type": "string"
|
|
327
|
+
"profilePicture": {
|
|
328
|
+
"type": "string",
|
|
329
|
+
"format": "binary"
|
|
353
330
|
},
|
|
354
|
-
"
|
|
331
|
+
"resume": {
|
|
355
332
|
"type": "string",
|
|
356
|
-
"format": "
|
|
333
|
+
"format": "binary"
|
|
357
334
|
},
|
|
358
|
-
"
|
|
359
|
-
"type": "
|
|
360
|
-
"
|
|
361
|
-
|
|
362
|
-
|
|
335
|
+
"documents": {
|
|
336
|
+
"type": "array",
|
|
337
|
+
"items": {
|
|
338
|
+
"type": "string",
|
|
339
|
+
"format": "binary"
|
|
340
|
+
}
|
|
363
341
|
}
|
|
364
342
|
},
|
|
365
|
-
"required": ["
|
|
343
|
+
"required": ["profilePicture", "documents"]
|
|
366
344
|
}
|
|
367
345
|
}
|
|
368
346
|
```
|
|
369
347
|
|
|
370
|
-
|
|
348
|
+
## 🌐 REST API Integration
|
|
349
|
+
|
|
350
|
+
### Implementation with Express.js and Swagger UI
|
|
371
351
|
|
|
372
352
|
```typescript
|
|
373
353
|
import express from 'express'
|
|
@@ -375,7 +355,7 @@ import swaggerUi from 'swagger-ui-express'
|
|
|
375
355
|
import { transform } from 'ts-class-to-openapi'
|
|
376
356
|
import { IsString, IsEmail, IsNotEmpty, IsInt, Min, Max } from 'class-validator'
|
|
377
357
|
|
|
378
|
-
//
|
|
358
|
+
// DTO definition with validation decorators
|
|
379
359
|
class User {
|
|
380
360
|
@IsString()
|
|
381
361
|
@IsNotEmpty()
|
|
@@ -401,14 +381,14 @@ class CreateUserDto {
|
|
|
401
381
|
|
|
402
382
|
const app = express()
|
|
403
383
|
|
|
404
|
-
//
|
|
384
|
+
// Schema generation from classes
|
|
405
385
|
const userSchema = transform(User)
|
|
406
386
|
const createUserSchema = transform(CreateUserDto)
|
|
407
387
|
|
|
408
|
-
//
|
|
409
|
-
const
|
|
388
|
+
// OpenAPI specification configuration
|
|
389
|
+
const swaggerSpecification = {
|
|
410
390
|
openapi: '3.1.0',
|
|
411
|
-
info: { title: '
|
|
391
|
+
info: { title: 'Management API', version: '1.0.0' },
|
|
412
392
|
components: {
|
|
413
393
|
schemas: {
|
|
414
394
|
[userSchema.name]: userSchema.schema,
|
|
@@ -417,17 +397,15 @@ const swaggerSpec = {
|
|
|
417
397
|
},
|
|
418
398
|
}
|
|
419
399
|
|
|
420
|
-
//
|
|
421
|
-
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(
|
|
400
|
+
// Swagger UI configuration
|
|
401
|
+
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecification))
|
|
422
402
|
|
|
423
403
|
app.listen(3000, () => {
|
|
424
|
-
console.log('API
|
|
404
|
+
console.log('API documentation available at http://localhost:3000/api-docs')
|
|
425
405
|
})
|
|
426
406
|
```
|
|
427
407
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
Here's a complete example of a POST endpoint that uses the generated schemas for both request validation and response structure:
|
|
408
|
+
### Complete POST endpoint implementation with schema validation
|
|
431
409
|
|
|
432
410
|
```typescript
|
|
433
411
|
import express from 'express'
|
|
@@ -443,7 +421,7 @@ import {
|
|
|
443
421
|
IsOptional,
|
|
444
422
|
} from 'class-validator'
|
|
445
423
|
|
|
446
|
-
//
|
|
424
|
+
// Domain entity definition
|
|
447
425
|
class User {
|
|
448
426
|
@IsInt()
|
|
449
427
|
@Min(1)
|
|
@@ -466,7 +444,7 @@ class User {
|
|
|
466
444
|
phone?: string
|
|
467
445
|
}
|
|
468
446
|
|
|
469
|
-
// DTO for
|
|
447
|
+
// DTO for user creation
|
|
470
448
|
class CreateUserDto {
|
|
471
449
|
@IsString()
|
|
472
450
|
@IsNotEmpty()
|
|
@@ -485,29 +463,22 @@ class CreateUserDto {
|
|
|
485
463
|
phone?: string
|
|
486
464
|
}
|
|
487
465
|
|
|
488
|
-
// Response wrapper (not transformed, defined manually in OpenAPI spec)
|
|
489
|
-
interface ApiResponse<T> {
|
|
490
|
-
data: T
|
|
491
|
-
success: boolean
|
|
492
|
-
}
|
|
493
|
-
|
|
494
466
|
const app = express()
|
|
495
467
|
app.use(express.json())
|
|
496
468
|
|
|
497
|
-
//
|
|
469
|
+
// Schema generation from classes
|
|
498
470
|
const userSchema = transform(User)
|
|
499
471
|
const createUserSchema = transform(CreateUserDto)
|
|
500
472
|
|
|
501
|
-
//
|
|
502
|
-
const
|
|
473
|
+
// Complete OpenAPI specification with POST endpoint
|
|
474
|
+
const swaggerSpecification = {
|
|
503
475
|
openapi: '3.1.0',
|
|
504
476
|
info: { title: 'User Management API', version: '1.0.0' },
|
|
505
477
|
components: {
|
|
506
478
|
schemas: {
|
|
507
479
|
[userSchema.name]: userSchema.schema,
|
|
508
480
|
[createUserSchema.name]: createUserSchema.schema,
|
|
509
|
-
|
|
510
|
-
UserApiResponse: {
|
|
481
|
+
UserResponse: {
|
|
511
482
|
type: 'object',
|
|
512
483
|
properties: {
|
|
513
484
|
data: { $ref: `#/components/schemas/${userSchema.name}` },
|
|
@@ -525,7 +496,9 @@ const swaggerSpec = {
|
|
|
525
496
|
required: true,
|
|
526
497
|
content: {
|
|
527
498
|
'application/json': {
|
|
528
|
-
schema: {
|
|
499
|
+
schema: {
|
|
500
|
+
$ref: `#/components/schemas/${createUserSchema.name}`,
|
|
501
|
+
},
|
|
529
502
|
},
|
|
530
503
|
},
|
|
531
504
|
},
|
|
@@ -534,7 +507,7 @@ const swaggerSpec = {
|
|
|
534
507
|
description: 'User created successfully',
|
|
535
508
|
content: {
|
|
536
509
|
'application/json': {
|
|
537
|
-
schema: { $ref: '#/components/schemas/
|
|
510
|
+
schema: { $ref: '#/components/schemas/UserResponse' },
|
|
538
511
|
},
|
|
539
512
|
},
|
|
540
513
|
},
|
|
@@ -547,21 +520,19 @@ const swaggerSpec = {
|
|
|
547
520
|
},
|
|
548
521
|
}
|
|
549
522
|
|
|
550
|
-
//
|
|
523
|
+
// POST endpoint implementation
|
|
551
524
|
app.post('/users', (req, res) => {
|
|
552
525
|
try {
|
|
553
|
-
// In a real application, you would validate the request body
|
|
554
|
-
// and save to database
|
|
555
526
|
const userData = req.body as CreateUserDto
|
|
556
527
|
|
|
557
|
-
//
|
|
528
|
+
// User creation simulation (replace with database logic)
|
|
558
529
|
const newUser: User = {
|
|
559
530
|
id: Math.floor(Math.random() * 1000) + 1,
|
|
560
531
|
...userData,
|
|
561
532
|
}
|
|
562
533
|
|
|
563
|
-
//
|
|
564
|
-
const response
|
|
534
|
+
// Response that complies with the defined schema
|
|
535
|
+
const response = {
|
|
565
536
|
data: newUser,
|
|
566
537
|
success: true,
|
|
567
538
|
}
|
|
@@ -576,400 +547,107 @@ app.post('/users', (req, res) => {
|
|
|
576
547
|
}
|
|
577
548
|
})
|
|
578
549
|
|
|
579
|
-
//
|
|
580
|
-
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(
|
|
550
|
+
// Swagger UI configuration
|
|
551
|
+
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecification))
|
|
581
552
|
|
|
582
553
|
app.listen(3000, () => {
|
|
583
|
-
console.log('API
|
|
554
|
+
console.log('API documentation available at http://localhost:3000/api-docs')
|
|
584
555
|
})
|
|
585
556
|
```
|
|
586
557
|
|
|
587
|
-
|
|
558
|
+
## 📖 API Reference
|
|
588
559
|
|
|
589
|
-
|
|
590
|
-
- **Response Schema**: Returns data in `{ data: User, success: boolean }` format
|
|
591
|
-
- **OpenAPI Documentation**: Complete Swagger specification with request/response schemas
|
|
592
|
-
- **Type Safety**: Full TypeScript support for request and response types
|
|
560
|
+
### `transform(class: Function)`
|
|
593
561
|
|
|
594
|
-
|
|
562
|
+
Transforms a class constructor function into an OpenAPI schema object.
|
|
595
563
|
|
|
596
|
-
|
|
597
|
-
import { transform } from 'ts-class-to-openapi'
|
|
598
|
-
import { IsNotEmpty, IsOptional } from 'class-validator'
|
|
564
|
+
**Parameters:**
|
|
599
565
|
|
|
600
|
-
|
|
601
|
-
class UploadFile {}
|
|
566
|
+
- `class: Function` - The class constructor function to transform
|
|
602
567
|
|
|
603
|
-
|
|
604
|
-
class ProfileUpload {
|
|
605
|
-
@IsNotEmpty()
|
|
606
|
-
profilePicture: UploadFile
|
|
568
|
+
**Returns:**
|
|
607
569
|
|
|
608
|
-
|
|
609
|
-
|
|
570
|
+
```typescript
|
|
571
|
+
{
|
|
572
|
+
name: string; // Class name
|
|
573
|
+
schema: {
|
|
574
|
+
type: "object";
|
|
575
|
+
properties: Record<string, any>;
|
|
576
|
+
required: string[];
|
|
577
|
+
}
|
|
610
578
|
}
|
|
611
|
-
|
|
612
|
-
// Generate schema
|
|
613
|
-
const schema = transform(ProfileUpload)
|
|
614
|
-
console.log(JSON.stringify(schema, null, 2))
|
|
615
579
|
```
|
|
616
580
|
|
|
617
|
-
**
|
|
618
|
-
|
|
619
|
-
```json
|
|
620
|
-
{
|
|
621
|
-
"name": "ProfileUpload",
|
|
622
|
-
"schema": {
|
|
623
|
-
"type": "object",
|
|
624
|
-
"properties": {
|
|
625
|
-
"profilePicture": {
|
|
626
|
-
"type": "string",
|
|
627
|
-
"format": "binary"
|
|
628
|
-
},
|
|
629
|
-
"resume": {
|
|
630
|
-
"type": "string",
|
|
631
|
-
"format": "binary"
|
|
632
|
-
}
|
|
633
|
-
},
|
|
634
|
-
"required": ["profilePicture"]
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
### Advanced Example with Nested Objects and Arrays
|
|
640
|
-
|
|
641
|
-
#### Pure TypeScript Classes
|
|
581
|
+
**Example:**
|
|
642
582
|
|
|
643
583
|
```typescript
|
|
644
584
|
import { transform } from 'ts-class-to-openapi'
|
|
585
|
+
import { User } from './entities/user.js'
|
|
645
586
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
permissions: string[]
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
class Address {
|
|
653
|
-
street: string
|
|
654
|
-
city: string
|
|
655
|
-
country: string
|
|
656
|
-
zipCode: string
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
class User {
|
|
660
|
-
id: number
|
|
661
|
-
name: string
|
|
662
|
-
email: string
|
|
663
|
-
age: number
|
|
664
|
-
isActive: boolean
|
|
665
|
-
tags: string[]
|
|
666
|
-
createdAt: Date
|
|
667
|
-
role: Role // Nested object
|
|
668
|
-
addresses: Address[] // Array of objects
|
|
669
|
-
files: Buffer[] // Binary files
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
const schema = transform(User)
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
#### Enhanced with class-validator
|
|
676
|
-
|
|
677
|
-
```typescript
|
|
678
|
-
import {
|
|
679
|
-
IsString,
|
|
680
|
-
IsInt,
|
|
681
|
-
IsEmail,
|
|
682
|
-
IsDate,
|
|
683
|
-
IsArray,
|
|
684
|
-
IsNotEmpty,
|
|
685
|
-
MinLength,
|
|
686
|
-
MaxLength,
|
|
687
|
-
Min,
|
|
688
|
-
Max,
|
|
689
|
-
ArrayNotEmpty,
|
|
690
|
-
} from 'class-validator'
|
|
691
|
-
|
|
692
|
-
class Role {
|
|
693
|
-
@IsInt()
|
|
694
|
-
@IsNotEmpty()
|
|
695
|
-
id: number
|
|
696
|
-
|
|
697
|
-
@IsString()
|
|
698
|
-
@MinLength(1)
|
|
699
|
-
@MaxLength(50)
|
|
700
|
-
name: string
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
class User {
|
|
704
|
-
@IsInt()
|
|
705
|
-
@IsNotEmpty()
|
|
706
|
-
@Min(1)
|
|
707
|
-
id: number
|
|
708
|
-
|
|
709
|
-
@IsString()
|
|
710
|
-
@MinLength(2)
|
|
711
|
-
@MaxLength(100)
|
|
712
|
-
name: string
|
|
713
|
-
|
|
714
|
-
@IsEmail()
|
|
715
|
-
email: string
|
|
716
|
-
|
|
717
|
-
@IsArray()
|
|
718
|
-
@ArrayNotEmpty()
|
|
719
|
-
tags: string[]
|
|
720
|
-
|
|
721
|
-
@IsDate()
|
|
722
|
-
createdAt: Date
|
|
723
|
-
|
|
724
|
-
@IsNotEmpty()
|
|
725
|
-
role: Role // Nested object
|
|
726
|
-
|
|
727
|
-
files: Buffer[] // Binary files
|
|
728
|
-
|
|
729
|
-
@IsNotEmpty()
|
|
730
|
-
avatar: UploadFile // Custom file upload type
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
const schema = transform(User)
|
|
734
|
-
```
|
|
735
|
-
|
|
736
|
-
**Generated Output:**
|
|
737
|
-
|
|
738
|
-
```json
|
|
739
|
-
{
|
|
740
|
-
"name": "User",
|
|
741
|
-
"schema": {
|
|
742
|
-
"type": "object",
|
|
743
|
-
"properties": {
|
|
744
|
-
"id": {
|
|
745
|
-
"type": "integer",
|
|
746
|
-
"format": "int32",
|
|
747
|
-
"minimum": 1
|
|
748
|
-
},
|
|
749
|
-
"name": {
|
|
750
|
-
"type": "string",
|
|
751
|
-
"minLength": 2,
|
|
752
|
-
"maxLength": 100
|
|
753
|
-
},
|
|
754
|
-
"email": {
|
|
755
|
-
"type": "string",
|
|
756
|
-
"format": "email"
|
|
757
|
-
},
|
|
758
|
-
"tags": {
|
|
759
|
-
"type": "array",
|
|
760
|
-
"items": {
|
|
761
|
-
"type": "string"
|
|
762
|
-
},
|
|
763
|
-
"minItems": 1
|
|
764
|
-
},
|
|
765
|
-
"createdAt": {
|
|
766
|
-
"type": "string",
|
|
767
|
-
"format": "date-time"
|
|
768
|
-
},
|
|
769
|
-
"role": {
|
|
770
|
-
"type": "object",
|
|
771
|
-
"properties": {
|
|
772
|
-
"id": {
|
|
773
|
-
"type": "integer",
|
|
774
|
-
"format": "int32"
|
|
775
|
-
},
|
|
776
|
-
"name": {
|
|
777
|
-
"type": "string",
|
|
778
|
-
"minLength": 1,
|
|
779
|
-
"maxLength": 50
|
|
780
|
-
}
|
|
781
|
-
},
|
|
782
|
-
"required": ["id"]
|
|
783
|
-
},
|
|
784
|
-
"files": {
|
|
785
|
-
"type": "array",
|
|
786
|
-
"items": {
|
|
787
|
-
"type": "string",
|
|
788
|
-
"format": "binary"
|
|
789
|
-
}
|
|
790
|
-
},
|
|
791
|
-
"avatar": {
|
|
792
|
-
"type": "string",
|
|
793
|
-
"format": "binary"
|
|
794
|
-
}
|
|
795
|
-
},
|
|
796
|
-
"required": ["id", "name", "email", "tags", "createdAt", "role", "files", "avatar"]
|
|
797
|
-
}
|
|
798
|
-
}
|
|
587
|
+
const result = transform(User)
|
|
588
|
+
console.log(result.name) // "User"
|
|
589
|
+
console.log(result.schema) // OpenAPI schema object
|
|
799
590
|
```
|
|
800
591
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
## 📊 Pure TypeScript vs Enhanced Mode Comparison
|
|
804
|
-
|
|
805
|
-
| Feature | Pure TypeScript | Enhanced (class-validator) |
|
|
806
|
-
| ---------------------- | ------------------------------------- | ------------------------------------ |
|
|
807
|
-
| **Dependencies** | Zero | Requires `class-validator` |
|
|
808
|
-
| **Configuration** | None | `experimentalDecorators: true` |
|
|
809
|
-
| **Type Detection** | Automatic | Automatic + Decorators |
|
|
810
|
-
| **Validation Rules** | Basic types only | Rich validation constraints |
|
|
811
|
-
| **Required Fields** | Based on TypeScript optional operator (`?`) | TypeScript optional operator + decorators |
|
|
812
|
-
| **String Constraints** | None | Min/max length, patterns |
|
|
813
|
-
| **Number Constraints** | None | Min/max values, positive |
|
|
814
|
-
| **Array Constraints** | None | Min/max items, non-empty |
|
|
815
|
-
| **Email Validation** | None | Email format validation |
|
|
816
|
-
| **Date Handling** | `date-time` format | `date-time` format |
|
|
817
|
-
| **Use Case** | Existing codebases, rapid prototyping | APIs with validation, robust schemas |
|
|
592
|
+
## 🎯 Required Properties Rules
|
|
818
593
|
|
|
819
|
-
###
|
|
594
|
+
### TypeScript Optional Operator (`?`)
|
|
820
595
|
|
|
821
|
-
|
|
596
|
+
The presence or absence of the TypeScript optional operator (`?`) determines whether a property is required:
|
|
822
597
|
|
|
823
598
|
```typescript
|
|
824
599
|
class User {
|
|
825
|
-
name: string
|
|
826
|
-
email: string
|
|
827
|
-
age
|
|
600
|
+
name: string // ✅ REQUIRED (no ? operator)
|
|
601
|
+
email: string // ✅ REQUIRED (no ? operator)
|
|
602
|
+
age?: number // ❌ OPTIONAL (has ? operator)
|
|
603
|
+
bio?: string // ❌ OPTIONAL (has ? operator)
|
|
828
604
|
}
|
|
829
|
-
// Generates: All properties required (no ? operator), basic types
|
|
830
|
-
```
|
|
831
|
-
|
|
832
|
-
**Enhanced Class:**
|
|
833
605
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
@IsString()
|
|
837
|
-
@IsNotEmpty()
|
|
838
|
-
name: string
|
|
839
|
-
|
|
840
|
-
@IsEmail()
|
|
841
|
-
email: string
|
|
842
|
-
|
|
843
|
-
@IsInt()
|
|
844
|
-
@Min(18)
|
|
845
|
-
age: number
|
|
846
|
-
}
|
|
847
|
-
// Generates: All properties required, email format validation, age minimum 18
|
|
606
|
+
// Generated schema:
|
|
607
|
+
// "required": ["name", "email"]
|
|
848
608
|
```
|
|
849
609
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
### Type Validation Decorators
|
|
853
|
-
|
|
854
|
-
| Decorator | Generated Schema Property | Description |
|
|
855
|
-
| --------------------- | ----------------------------------------------- | --------------------------- |
|
|
856
|
-
| `@IsString()` | `type: "string"` | String type validation |
|
|
857
|
-
| `@IsInt()` | `type: "integer", format: "int32"` | Integer type validation |
|
|
858
|
-
| `@IsNumber()` | `type: "number", format: "double"` | Number type validation |
|
|
859
|
-
| `@IsBoolean()` | `type: "boolean"` | Boolean type validation |
|
|
860
|
-
| `@IsEmail()` | `type: "string", format: "email"` | Email format validation |
|
|
861
|
-
| `@IsDate()` | `type: "string", format: "date-time"` | Date-time format validation |
|
|
862
|
-
| `@IsEnum(enumObject)` | `type: "string/number/boolean", enum: [values]` | Enum constraint validation |
|
|
863
|
-
|
|
864
|
-
### Enum Validation with @IsEnum
|
|
610
|
+
### Override via class-validator Decorators
|
|
865
611
|
|
|
866
|
-
|
|
612
|
+
class-validator decorators can override the default behavior of the TypeScript optional operator:
|
|
867
613
|
|
|
868
614
|
```typescript
|
|
869
|
-
import {
|
|
870
|
-
import { IsEnum, IsNotEmpty, IsArray } from 'class-validator'
|
|
871
|
-
|
|
872
|
-
// String enum
|
|
873
|
-
enum UserRole {
|
|
874
|
-
ADMIN = 'admin',
|
|
875
|
-
USER = 'user',
|
|
876
|
-
MODERATOR = 'moderator',
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
// Numeric enum
|
|
880
|
-
enum Priority {
|
|
881
|
-
LOW = 1,
|
|
882
|
-
MEDIUM = 2,
|
|
883
|
-
HIGH = 3,
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
// Auto-incremented enum
|
|
887
|
-
enum Size {
|
|
888
|
-
SMALL, // 0
|
|
889
|
-
MEDIUM, // 1
|
|
890
|
-
LARGE, // 2
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
// Object enum with 'as const'
|
|
894
|
-
const Status = {
|
|
895
|
-
ACTIVE: 'active',
|
|
896
|
-
INACTIVE: 'inactive',
|
|
897
|
-
PENDING: 'pending',
|
|
898
|
-
} as const
|
|
615
|
+
import { IsNotEmpty, IsOptional } from 'class-validator'
|
|
899
616
|
|
|
900
|
-
class
|
|
901
|
-
@IsEnum(UserRole)
|
|
617
|
+
class User {
|
|
902
618
|
@IsNotEmpty()
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
@IsEnum(Priority)
|
|
906
|
-
priority?: Priority // Optional enum
|
|
907
|
-
|
|
908
|
-
@IsEnum(Size)
|
|
909
|
-
size?: Size // Auto-incremented enum
|
|
619
|
+
requiredField?: string // ✅ REQUIRED (@IsNotEmpty overrides ?)
|
|
910
620
|
|
|
911
|
-
@
|
|
912
|
-
|
|
621
|
+
@IsOptional()
|
|
622
|
+
optionalField: string // ❌ OPTIONAL (@IsOptional overrides absence of ?)
|
|
913
623
|
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
allowedRoles?: UserRole[] // Array of enums
|
|
624
|
+
normalField: string // ✅ REQUIRED (no ? operator)
|
|
625
|
+
normalOptional?: string // ❌ OPTIONAL (has ? operator)
|
|
917
626
|
}
|
|
918
627
|
|
|
919
|
-
|
|
628
|
+
// Generated schema:
|
|
629
|
+
// "required": ["requiredField", "normalField"]
|
|
920
630
|
```
|
|
921
631
|
|
|
922
|
-
|
|
632
|
+
## 🎨 Supported Decorators
|
|
923
633
|
|
|
924
|
-
|
|
925
|
-
{
|
|
926
|
-
"name": "TaskEntity",
|
|
927
|
-
"schema": {
|
|
928
|
-
"type": "object",
|
|
929
|
-
"properties": {
|
|
930
|
-
"assignedRole": {
|
|
931
|
-
"type": "string",
|
|
932
|
-
"enum": ["admin", "user", "moderator"]
|
|
933
|
-
},
|
|
934
|
-
"priority": {
|
|
935
|
-
"type": "number",
|
|
936
|
-
"enum": [1, 2, 3]
|
|
937
|
-
},
|
|
938
|
-
"size": {
|
|
939
|
-
"type": "number",
|
|
940
|
-
"enum": [0, 1, 2]
|
|
941
|
-
},
|
|
942
|
-
"status": {
|
|
943
|
-
"type": "string",
|
|
944
|
-
"enum": ["active", "inactive", "pending"]
|
|
945
|
-
},
|
|
946
|
-
"allowedRoles": {
|
|
947
|
-
"type": "array",
|
|
948
|
-
"items": {
|
|
949
|
-
"type": "string",
|
|
950
|
-
"enum": ["admin", "user", "moderator"]
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
},
|
|
954
|
-
"required": ["assignedRole"]
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
```
|
|
958
|
-
|
|
959
|
-
**Supported Enum Types:**
|
|
634
|
+
### Type Validation Decorators
|
|
960
635
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
636
|
+
| Decorator | Generated Schema Property | Description |
|
|
637
|
+
| --------------------- | ----------------------------------------------- | -------------------------- |
|
|
638
|
+
| `@IsString()` | `type: "string"` | String type validation |
|
|
639
|
+
| `@IsInt()` | `type: "integer", format: "int32"` | Integer type validation |
|
|
640
|
+
| `@IsNumber()` | `type: "number", format: "double"` | Number type validation |
|
|
641
|
+
| `@IsBoolean()` | `type: "boolean"` | Boolean type validation |
|
|
642
|
+
| `@IsEmail()` | `type: "string", format: "email"` | Email format validation |
|
|
643
|
+
| `@IsDate()` | `type: "string", format: "date-time"` | Date format validation |
|
|
644
|
+
| `@IsEnum(enumObject)` | `type: "string/number/boolean", enum: [values]` | Enum constraint validation |
|
|
967
645
|
|
|
968
646
|
### String Validation Decorators
|
|
969
647
|
|
|
970
648
|
| Decorator | Generated Schema Property | Description |
|
|
971
649
|
| ------------------- | -------------------------------- | --------------------- |
|
|
972
|
-
| `@IsNotEmpty()` |
|
|
650
|
+
| `@IsNotEmpty()` | Added to `required` array | Field is required |
|
|
973
651
|
| `@MinLength(n)` | `minLength: n` | Minimum string length |
|
|
974
652
|
| `@MaxLength(n)` | `maxLength: n` | Maximum string length |
|
|
975
653
|
| `@Length(min, max)` | `minLength: min, maxLength: max` | String length range |
|
|
@@ -991,259 +669,146 @@ const result = transform(TaskEntity)
|
|
|
991
669
|
| `@ArrayMinSize(n)` | `minItems: n` | Minimum array size |
|
|
992
670
|
| `@ArrayMaxSize(n)` | `maxItems: n` | Maximum array size |
|
|
993
671
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
| TypeScript Type | Generated OpenAPI Schema | Description |
|
|
997
|
-
| --------------- | ------------------------------------- | ------------------------------ |
|
|
998
|
-
| `Date` | `type: "string", format: "date-time"` | ISO date-time string |
|
|
999
|
-
| `Buffer` | `type: "string", format: "binary"` | Binary data |
|
|
1000
|
-
| `Uint8Array` | `type: "string", format: "binary"` | Binary array |
|
|
1001
|
-
| `UploadFile` | `type: "string", format: "binary"` | Custom file upload type |
|
|
1002
|
-
| `CustomClass` | Nested object schema | Recursive class transformation |
|
|
1003
|
-
| `Type[]` | Array with typed items | Array of specific type |
|
|
672
|
+
## 📊 Comparison: Pure TypeScript vs Enhanced Mode
|
|
1004
673
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
// Special types
|
|
1017
|
-
createdAt: Date // → type: "string", format: "date-time"
|
|
1018
|
-
file: Buffer // → type: "string", format: "binary"
|
|
1019
|
-
|
|
1020
|
-
// Arrays
|
|
1021
|
-
tags: string[] // → type: "array", items: { type: "string" }
|
|
1022
|
-
scores: number[] // → type: "array", items: { type: "number" }
|
|
1023
|
-
|
|
1024
|
-
// Objects
|
|
1025
|
-
metadata: object // → type: "object"
|
|
1026
|
-
data: any // → No schema constraints
|
|
1027
|
-
|
|
1028
|
-
// Nested classes (automatically transformed)
|
|
1029
|
-
profile: UserProfile // → Nested object schema
|
|
1030
|
-
}
|
|
1031
|
-
```
|
|
1032
|
-
|
|
1033
|
-
## 📁 File Upload Support
|
|
1034
|
-
|
|
1035
|
-
The library provides built-in support for file uploads with automatic binary format mapping:
|
|
1036
|
-
|
|
1037
|
-
```typescript
|
|
1038
|
-
import { transform } from 'ts-class-to-openapi'
|
|
1039
|
-
import { IsNotEmpty, IsArray, IsOptional } from 'class-validator'
|
|
1040
|
-
|
|
1041
|
-
// Define your custom file type
|
|
1042
|
-
class UploadFile {}
|
|
1043
|
-
|
|
1044
|
-
class DocumentUpload {
|
|
1045
|
-
@IsNotEmpty()
|
|
1046
|
-
document: UploadFile // Single file upload (required)
|
|
1047
|
-
|
|
1048
|
-
@IsArray()
|
|
1049
|
-
attachments: UploadFile[] // Multiple file uploads
|
|
1050
|
-
|
|
1051
|
-
@IsOptional()
|
|
1052
|
-
avatar: UploadFile // Optional file upload
|
|
1053
|
-
}
|
|
674
|
+
| Feature | Pure TypeScript | Enhanced (class-validator) |
|
|
675
|
+
| ---------------------- | ------------------------------------- | ------------------------------------ |
|
|
676
|
+
| **Dependencies** | Zero | Requires `class-validator` |
|
|
677
|
+
| **Configuration** | None | `experimentalDecorators: true` |
|
|
678
|
+
| **Type Detection** | Automatic | Automatic + Decorators |
|
|
679
|
+
| **Validation Rules** | Basic types only | Rich validation constraints |
|
|
680
|
+
| **Required Fields** | Based on optional operator (`?`) | Optional operator + decorators |
|
|
681
|
+
| **String Constraints** | None | Min/max length, patterns |
|
|
682
|
+
| **Number Constraints** | None | Min/max values, positive |
|
|
683
|
+
| **Array Constraints** | None | Min/max items, non-empty |
|
|
684
|
+
| **Use Case** | Existing codebases, rapid prototyping | APIs with validation, robust schemas |
|
|
1054
685
|
|
|
1055
|
-
|
|
1056
|
-
const schema = transform(DocumentUpload)
|
|
1057
|
-
console.log(JSON.stringify(schema, null, 2))
|
|
1058
|
-
```
|
|
686
|
+
## ⚙️ Configuration
|
|
1059
687
|
|
|
1060
|
-
|
|
688
|
+
### Requirements
|
|
1061
689
|
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
"
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
"type": "string",
|
|
1070
|
-
"format": "binary"
|
|
1071
|
-
},
|
|
1072
|
-
"attachments": {
|
|
1073
|
-
"type": "array",
|
|
1074
|
-
"items": {
|
|
1075
|
-
"type": "string",
|
|
1076
|
-
"format": "binary"
|
|
1077
|
-
}
|
|
1078
|
-
},
|
|
1079
|
-
"avatar": {
|
|
1080
|
-
"type": "string",
|
|
1081
|
-
"format": "binary"
|
|
1082
|
-
}
|
|
1083
|
-
},
|
|
1084
|
-
"required": ["document", "attachments"]
|
|
690
|
+
- Node.js >= 14.0.0
|
|
691
|
+
- TypeScript with minimal compiler options in `tsconfig.json`:
|
|
692
|
+
```json
|
|
693
|
+
{
|
|
694
|
+
"compilerOptions": {
|
|
695
|
+
"experimentalDecorators": true
|
|
696
|
+
}
|
|
1085
697
|
}
|
|
1086
|
-
|
|
1087
|
-
```
|
|
1088
|
-
|
|
1089
|
-
### Supported File Types
|
|
1090
|
-
|
|
1091
|
-
The following types are automatically converted to binary format:
|
|
1092
|
-
|
|
1093
|
-
- `Buffer` - Node.js Buffer objects
|
|
1094
|
-
- `Uint8Array` - Typed arrays
|
|
1095
|
-
- `UploadFile` - Custom file upload classes
|
|
1096
|
-
- Any class ending with "File" suffix (e.g., `ImageFile`, `VideoFile`)
|
|
1097
|
-
|
|
1098
|
-
## 📖 API Reference
|
|
1099
|
-
|
|
1100
|
-
### `transform(cls: Function)`
|
|
698
|
+
```
|
|
1101
699
|
|
|
1102
|
-
|
|
700
|
+
> **Note**: The `experimentalDecorators` option is only required if you plan to use class-validator decorators. Pure TypeScript classes work without special configuration.
|
|
1103
701
|
|
|
1104
|
-
|
|
702
|
+
### TypeScript Support
|
|
1105
703
|
|
|
1106
|
-
|
|
704
|
+
This library works with:
|
|
1107
705
|
|
|
1108
|
-
|
|
706
|
+
- ✅ Pure TypeScript classes (no decorators needed)
|
|
707
|
+
- ✅ class-validator decorated classes
|
|
708
|
+
- ✅ Mixed usage (some classes with decorators, some without)
|
|
709
|
+
- ✅ All TypeScript types: primitives, arrays, enums, nested objects
|
|
1109
710
|
|
|
1110
|
-
|
|
1111
|
-
{
|
|
1112
|
-
name: string; // Class name
|
|
1113
|
-
schema: {
|
|
1114
|
-
type: "object";
|
|
1115
|
-
properties: Record<string, any>;
|
|
1116
|
-
required: string[];
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
```
|
|
711
|
+
### Module Compatibility
|
|
1120
712
|
|
|
1121
|
-
**
|
|
713
|
+
This library is **fully compatible with CommonJS and ESM**:
|
|
1122
714
|
|
|
1123
715
|
```typescript
|
|
716
|
+
// ESM (recommended)
|
|
1124
717
|
import { transform } from 'ts-class-to-openapi'
|
|
1125
|
-
import { User } from './entities/user.js'
|
|
1126
718
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
console.log(result.schema) // OpenAPI schema object
|
|
719
|
+
// CommonJS
|
|
720
|
+
const { transform } = require('ts-class-to-openapi')
|
|
1130
721
|
```
|
|
1131
722
|
|
|
1132
|
-
##
|
|
723
|
+
## 🔧 Troubleshooting
|
|
1133
724
|
|
|
1134
|
-
|
|
725
|
+
### Common Issues
|
|
1135
726
|
|
|
1136
|
-
|
|
727
|
+
**Error: "Cannot find module 'ts-class-to-openapi'"**
|
|
1137
728
|
|
|
1138
|
-
|
|
729
|
+
```bash
|
|
730
|
+
npm install ts-class-to-openapi
|
|
731
|
+
```
|
|
1139
732
|
|
|
1140
|
-
|
|
1141
|
-
class User {
|
|
1142
|
-
name: string // ✅ REQUIRED (no ? operator)
|
|
1143
|
-
email: string // ✅ REQUIRED (no ? operator)
|
|
1144
|
-
age?: number // ❌ OPTIONAL (has ? operator)
|
|
1145
|
-
bio?: string // ❌ OPTIONAL (has ? operator)
|
|
1146
|
-
}
|
|
733
|
+
**Error: "Cannot find module 'class-validator'"**
|
|
1147
734
|
|
|
1148
|
-
|
|
1149
|
-
|
|
735
|
+
This dependency is only necessary for using validation decorators:
|
|
736
|
+
|
|
737
|
+
```bash
|
|
738
|
+
npm install class-validator
|
|
1150
739
|
```
|
|
1151
740
|
|
|
1152
|
-
|
|
741
|
+
**Error: "Experimental decorators warning"**
|
|
1153
742
|
|
|
1154
|
-
|
|
743
|
+
Add the following configuration to the `tsconfig.json` file:
|
|
1155
744
|
|
|
1156
|
-
```
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
requiredField?: string // ✅ REQUIRED (@IsNotEmpty overrides ?)
|
|
1162
|
-
|
|
1163
|
-
@IsOptional()
|
|
1164
|
-
optionalField: string // ❌ OPTIONAL (@IsOptional overrides no ?)
|
|
1165
|
-
|
|
1166
|
-
normalField: string // ✅ REQUIRED (no ? operator)
|
|
1167
|
-
normalOptional?: string // ❌ OPTIONAL (has ? operator)
|
|
745
|
+
```json
|
|
746
|
+
{
|
|
747
|
+
"compilerOptions": {
|
|
748
|
+
"experimentalDecorators": true
|
|
749
|
+
}
|
|
1168
750
|
}
|
|
1169
|
-
|
|
1170
|
-
// Generated schema:
|
|
1171
|
-
// "required": ["requiredField", "normalField"]
|
|
1172
751
|
```
|
|
1173
752
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
Array properties follow the same rules, with additional decorators:
|
|
1177
|
-
|
|
1178
|
-
```typescript
|
|
1179
|
-
import { ArrayNotEmpty } from 'class-validator'
|
|
753
|
+
**Empty schema generated**
|
|
1180
754
|
|
|
1181
|
-
class
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
categories?: string[] // ✅ REQUIRED (@ArrayNotEmpty overrides ?)
|
|
1186
|
-
|
|
1187
|
-
optionalTags?: string[] // ❌ OPTIONAL (has ? operator)
|
|
1188
|
-
}
|
|
755
|
+
- For pure TypeScript classes: Verify that the class contains properties with correctly defined types
|
|
756
|
+
- For classes with decorators: Confirm that the class includes class-validator decorators
|
|
757
|
+
- Verify that the class is correctly exported and imported
|
|
758
|
+
- Confirm that TypeScript compilation runs without errors
|
|
1189
759
|
|
|
1190
|
-
|
|
1191
|
-
// "required": ["tags", "categories"]
|
|
1192
|
-
```
|
|
760
|
+
**Works without decorators but wants validation?**
|
|
1193
761
|
|
|
1194
|
-
|
|
762
|
+
Pure TypeScript classes work immediately, but if you want enhanced validation schemas:
|
|
1195
763
|
|
|
1196
|
-
1.
|
|
1197
|
-
2.
|
|
1198
|
-
3.
|
|
1199
|
-
4. **`@IsOptional()`** → Forces **OPTIONAL** (overrides no `?`)
|
|
764
|
+
1. Install class-validator: `npm install class-validator`
|
|
765
|
+
2. Add decorators to the corresponding properties
|
|
766
|
+
3. Enable `experimentalDecorators: true` in the tsconfig.json file
|
|
1200
767
|
|
|
1201
768
|
## 🌟 Advanced Features
|
|
1202
769
|
|
|
1203
|
-
- ✅ **
|
|
1204
|
-
- ✅ **Zero
|
|
1205
|
-
- ✅ **
|
|
1206
|
-
- ✅ **Nested
|
|
1207
|
-
- ✅ **
|
|
1208
|
-
- ✅ **
|
|
1209
|
-
- ✅ **Type
|
|
1210
|
-
- ✅ **Framework
|
|
1211
|
-
- ✅ **Comprehensive Coverage** - Supports all major class-validator decorators
|
|
1212
|
-
- ✅ **Flexible Usage** - Use with or without validation decorators
|
|
770
|
+
- ✅ **Native pure TypeScript support** - Compatible with any TypeScript class without requiring decorators
|
|
771
|
+
- ✅ **Zero runtime dependencies** - Uses TypeScript Compiler API instead of reflect-metadata
|
|
772
|
+
- ✅ **Optimized performance** - Singleton pattern implementation with caching system for repeated transformations
|
|
773
|
+
- ✅ **Nested object processing** - Automatic handling of complex relationships between objects
|
|
774
|
+
- ✅ **Full typed array support** - Comprehensive compatibility with arrays and validation constraints
|
|
775
|
+
- ✅ **Integrated caching system** - Avoids reprocessing the same classes
|
|
776
|
+
- ✅ **Type safety** - Complete TypeScript support with precise type definitions
|
|
777
|
+
- ✅ **Framework agnostic** - Compatible with any TypeScript project configuration
|
|
1213
778
|
|
|
1214
779
|
## 🔄 Migration Guide
|
|
1215
780
|
|
|
1216
|
-
###
|
|
781
|
+
### Migration from reflect-metadata Based Solutions
|
|
1217
782
|
|
|
1218
|
-
|
|
783
|
+
For projects using solutions that require `reflect-metadata`:
|
|
1219
784
|
|
|
1220
|
-
**
|
|
785
|
+
**Previous implementation (with reflect-metadata):**
|
|
1221
786
|
|
|
1222
787
|
```typescript
|
|
1223
788
|
import 'reflect-metadata'
|
|
1224
789
|
import { getMetadataStorage } from 'class-validator'
|
|
1225
790
|
|
|
1226
|
-
// Complex
|
|
791
|
+
// Complex configuration required
|
|
1227
792
|
const schema = transformClassToSchema(User)
|
|
1228
793
|
```
|
|
1229
794
|
|
|
1230
|
-
**
|
|
795
|
+
**New implementation (with ts-class-to-openapi):**
|
|
1231
796
|
|
|
1232
797
|
```typescript
|
|
1233
798
|
import { transform } from 'ts-class-to-openapi'
|
|
1234
799
|
|
|
1235
|
-
//
|
|
800
|
+
// Simplified API
|
|
1236
801
|
const schema = transform(User)
|
|
1237
802
|
```
|
|
1238
803
|
|
|
1239
|
-
### New: Pure TypeScript Support
|
|
804
|
+
### New Functionality: Pure TypeScript Support
|
|
1240
805
|
|
|
1241
|
-
The
|
|
806
|
+
The main advantage lies in the ability to transform **any TypeScript class** without requiring decorators:
|
|
1242
807
|
|
|
1243
|
-
**
|
|
808
|
+
**Previous limitation (mandatory decorators):**
|
|
1244
809
|
|
|
1245
810
|
```typescript
|
|
1246
|
-
// This would NOT work with traditional solutions
|
|
811
|
+
// This approach would NOT work with traditional solutions
|
|
1247
812
|
class LegacyUser {
|
|
1248
813
|
id: number
|
|
1249
814
|
name: string
|
|
@@ -1251,92 +816,21 @@ class LegacyUser {
|
|
|
1251
816
|
}
|
|
1252
817
|
```
|
|
1253
818
|
|
|
1254
|
-
**
|
|
819
|
+
**Current implementation (immediate functionality):**
|
|
1255
820
|
|
|
1256
821
|
```typescript
|
|
1257
822
|
import { transform } from 'ts-class-to-openapi'
|
|
1258
823
|
|
|
1259
|
-
//
|
|
824
|
+
// Ready-to-use functionality
|
|
1260
825
|
class LegacyUser {
|
|
1261
826
|
id: number
|
|
1262
827
|
name: string
|
|
1263
828
|
email: string
|
|
1264
829
|
}
|
|
1265
830
|
|
|
1266
|
-
const schema = transform(LegacyUser) // ✅
|
|
831
|
+
const schema = transform(LegacyUser) // ✅ Successful operation
|
|
1267
832
|
```
|
|
1268
833
|
|
|
1269
|
-
### Migration Steps
|
|
1270
|
-
|
|
1271
|
-
1. **Remove reflect-metadata imports** from your entities
|
|
1272
|
-
2. **Remove `emitDecoratorMetadata: true`** from tsconfig.json (optional)
|
|
1273
|
-
3. **Update transformation code** to use the new API
|
|
1274
|
-
4. **Remove reflect-metadata dependency** from package.json
|
|
1275
|
-
5. **Optional**: Keep decorators for enhanced validation or remove them entirely
|
|
1276
|
-
|
|
1277
|
-
### TypeScript Configuration
|
|
1278
|
-
|
|
1279
|
-
You only need minimal TypeScript configuration:
|
|
1280
|
-
|
|
1281
|
-
```json
|
|
1282
|
-
{
|
|
1283
|
-
"compilerOptions": {
|
|
1284
|
-
"experimentalDecorators": true
|
|
1285
|
-
// emitDecoratorMetadata: true ← NOT REQUIRED!
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
```
|
|
1289
|
-
|
|
1290
|
-
## 🔧 Troubleshooting
|
|
1291
|
-
|
|
1292
|
-
### Common Issues
|
|
1293
|
-
|
|
1294
|
-
**Error: "Cannot find module 'ts-class-to-openapi'"**
|
|
1295
|
-
|
|
1296
|
-
```bash
|
|
1297
|
-
npm install ts-class-to-openapi
|
|
1298
|
-
```
|
|
1299
|
-
|
|
1300
|
-
**Error: "Cannot find module 'class-validator'"**
|
|
1301
|
-
|
|
1302
|
-
This is only needed if you want to use validation decorators:
|
|
1303
|
-
|
|
1304
|
-
```bash
|
|
1305
|
-
npm install class-validator
|
|
1306
|
-
```
|
|
1307
|
-
|
|
1308
|
-
**Error: "Experimental decorators warning"**
|
|
1309
|
-
Add to your `tsconfig.json`:
|
|
1310
|
-
|
|
1311
|
-
```json
|
|
1312
|
-
{
|
|
1313
|
-
"compilerOptions": {
|
|
1314
|
-
"experimentalDecorators": true
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
```
|
|
1318
|
-
|
|
1319
|
-
**Empty schema generated**
|
|
1320
|
-
|
|
1321
|
-
- For pure TypeScript classes: Ensure your class has properly typed properties
|
|
1322
|
-
- For class-validator enhanced: Ensure your class has class-validator decorators
|
|
1323
|
-
- Check that the class is properly exported/imported
|
|
1324
|
-
- Verify TypeScript compilation is working
|
|
1325
|
-
|
|
1326
|
-
**Works without decorators but want validation?**
|
|
1327
|
-
|
|
1328
|
-
Pure TypeScript classes work immediately, but if you want enhanced validation schemas:
|
|
1329
|
-
|
|
1330
|
-
1. Install class-validator: `npm install class-validator`
|
|
1331
|
-
2. Add decorators to your properties
|
|
1332
|
-
3. Enable `experimentalDecorators: true` in tsconfig.json
|
|
1333
|
-
|
|
1334
|
-
**Nested objects not working**
|
|
1335
|
-
|
|
1336
|
-
- Make sure nested classes are in the same project
|
|
1337
|
-
- Ensure nested classes have their own decorators
|
|
1338
|
-
- Check file paths and imports
|
|
1339
|
-
|
|
1340
834
|
## 📄 License
|
|
1341
835
|
|
|
1342
836
|
MIT
|