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