@hazeljs/swagger 0.8.5 β 0.8.7
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 +78 -516
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/openapi-document.test.d.ts +2 -0
- package/dist/openapi-document.test.d.ts.map +1 -0
- package/dist/openapi-document.test.js +42 -0
- package/dist/swagger-config.d.ts +5 -0
- package/dist/swagger-config.d.ts.map +1 -0
- package/dist/swagger-config.js +15 -0
- package/dist/swagger.controller.d.ts +2 -1
- package/dist/swagger.controller.d.ts.map +1 -1
- package/dist/swagger.controller.js +44 -85
- package/dist/swagger.controller.test.js +41 -156
- package/dist/swagger.module.d.ts +7 -0
- package/dist/swagger.module.d.ts.map +1 -1
- package/dist/swagger.module.js +16 -0
- package/dist/swagger.service.d.ts +14 -27
- package/dist/swagger.service.d.ts.map +1 -1
- package/dist/swagger.service.js +143 -162
- package/dist/swagger.service.test.js +164 -22
- package/dist/swagger.types.d.ts +52 -1
- package/dist/swagger.types.d.ts.map +1 -1
- package/package.json +4 -8
- package/dist/src/index.d.ts +0 -8
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -15
- package/dist/src/swagger.controller.d.ts +0 -12
- package/dist/src/swagger.controller.d.ts.map +0 -1
- package/dist/src/swagger.controller.js +0 -238
- package/dist/src/swagger.decorator.d.ts +0 -7
- package/dist/src/swagger.decorator.d.ts.map +0 -1
- package/dist/src/swagger.decorator.js +0 -26
- package/dist/src/swagger.module.d.ts +0 -5
- package/dist/src/swagger.module.d.ts.map +0 -1
- package/dist/src/swagger.module.js +0 -30
- package/dist/src/swagger.service.d.ts +0 -24
- package/dist/src/swagger.service.d.ts.map +0 -1
- package/dist/src/swagger.service.js +0 -117
- package/dist/src/swagger.types.d.ts +0 -50
- package/dist/src/swagger.types.d.ts.map +0 -1
- package/dist/src/swagger.types.js +0 -2
- package/dist/tsconfig.tsbuildinfo +0 -1
package/README.md
CHANGED
|
@@ -1,564 +1,139 @@
|
|
|
1
1
|
# @hazeljs/swagger
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Add `@ApiOperation` and `@ApiResponse` β get Swagger UI. No manual OpenAPI JSON. Decorators on your controllers, interactive docs at `/api-docs`. Your frontend team will thank you.
|
|
3
|
+
OpenAPI 3.0 documents and Swagger UI for HazelJS: class-level `@Swagger`, method-level `@ApiOperation`, automatic operation stubs for undocumented routes, and a small runtime config API.
|
|
6
4
|
|
|
7
5
|
[](https://www.npmjs.com/package/@hazeljs/swagger)
|
|
8
|
-
[](https://www.npmjs.com/package/@hazeljs/swagger)
|
|
9
6
|
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
10
7
|
|
|
11
|
-
## Features
|
|
12
|
-
|
|
13
|
-
- π **Auto-Generated Docs** - Automatic OpenAPI spec generation
|
|
14
|
-
- π¨ **Swagger UI** - Interactive API explorer
|
|
15
|
-
- π·οΈ **Decorator-Based** - Document APIs with decorators
|
|
16
|
-
- π **Type Safety** - TypeScript integration
|
|
17
|
-
- π **Authentication** - Document auth requirements
|
|
18
|
-
- π **Request/Response Examples** - Add example payloads
|
|
19
|
-
- π― **Tags & Groups** - Organize endpoints
|
|
20
|
-
- π **Multiple Formats** - JSON, YAML export
|
|
21
|
-
|
|
22
8
|
## Installation
|
|
23
9
|
|
|
24
10
|
```bash
|
|
25
|
-
npm install @hazeljs/swagger
|
|
11
|
+
npm install @hazeljs/swagger @hazeljs/core
|
|
26
12
|
```
|
|
27
13
|
|
|
28
|
-
## Quick
|
|
14
|
+
## Quick start
|
|
29
15
|
|
|
30
|
-
### 1.
|
|
16
|
+
### 1. Import the module and register your app root
|
|
31
17
|
|
|
32
18
|
```typescript
|
|
33
19
|
import { HazelModule } from '@hazeljs/core';
|
|
34
20
|
import { SwaggerModule } from '@hazeljs/swagger';
|
|
35
21
|
|
|
36
22
|
@HazelModule({
|
|
37
|
-
imports: [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
description: 'API documentation',
|
|
41
|
-
version: '1.0.0',
|
|
42
|
-
path: '/api-docs',
|
|
43
|
-
}),
|
|
23
|
+
imports: [SwaggerModule],
|
|
24
|
+
controllers: [
|
|
25
|
+
/* ... */
|
|
44
26
|
],
|
|
45
27
|
})
|
|
46
28
|
export class AppModule {}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### 2. Document Controllers
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
import { Controller, Get, Post, Body, Param } from '@hazeljs/core';
|
|
53
|
-
import { ApiOperation, ApiResponse, ApiTags } from '@hazeljs/swagger';
|
|
54
|
-
|
|
55
|
-
@Controller('/users')
|
|
56
|
-
@ApiTags('Users')
|
|
57
|
-
export class UserController {
|
|
58
|
-
@Get()
|
|
59
|
-
@ApiOperation({ summary: 'Get all users' })
|
|
60
|
-
@ApiResponse({ status: 200, description: 'List of users' })
|
|
61
|
-
findAll() {
|
|
62
|
-
return { users: [] };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@Get('/:id')
|
|
66
|
-
@ApiOperation({ summary: 'Get user by ID' })
|
|
67
|
-
@ApiResponse({ status: 200, description: 'User found' })
|
|
68
|
-
@ApiResponse({ status: 404, description: 'User not found' })
|
|
69
|
-
findOne(@Param('id') id: string) {
|
|
70
|
-
return { id, name: 'John Doe' };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
@Post()
|
|
74
|
-
@ApiOperation({ summary: 'Create a new user' })
|
|
75
|
-
@ApiResponse({ status: 201, description: 'User created' })
|
|
76
|
-
@ApiResponse({ status: 400, description: 'Invalid input' })
|
|
77
|
-
create(@Body() createUserDto: CreateUserDto) {
|
|
78
|
-
return createUserDto;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### 3. Access Documentation
|
|
84
|
-
|
|
85
|
-
Navigate to `http://localhost:3000/api-docs` to view the interactive Swagger UI.
|
|
86
|
-
|
|
87
|
-
## Decorators
|
|
88
|
-
|
|
89
|
-
### @ApiTags()
|
|
90
|
-
|
|
91
|
-
Group endpoints by tags:
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
@Controller('/products')
|
|
95
|
-
@ApiTags('Products', 'Catalog')
|
|
96
|
-
export class ProductController {
|
|
97
|
-
// All endpoints will be tagged with 'Products' and 'Catalog'
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### @ApiOperation()
|
|
102
|
-
|
|
103
|
-
Document endpoint details:
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
@Get('/search')
|
|
107
|
-
@ApiOperation({
|
|
108
|
-
summary: 'Search products',
|
|
109
|
-
description: 'Search for products by name, category, or tags',
|
|
110
|
-
operationId: 'searchProducts',
|
|
111
|
-
})
|
|
112
|
-
searchProducts() {
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### @ApiResponse()
|
|
118
|
-
|
|
119
|
-
Document response types:
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
@Get('/:id')
|
|
123
|
-
@ApiResponse({
|
|
124
|
-
status: 200,
|
|
125
|
-
description: 'Product found',
|
|
126
|
-
type: ProductDto,
|
|
127
|
-
})
|
|
128
|
-
@ApiResponse({
|
|
129
|
-
status: 404,
|
|
130
|
-
description: 'Product not found',
|
|
131
|
-
schema: {
|
|
132
|
-
type: 'object',
|
|
133
|
-
properties: {
|
|
134
|
-
statusCode: { type: 'number' },
|
|
135
|
-
message: { type: 'string' },
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
})
|
|
139
|
-
findOne(@Param('id') id: string) {
|
|
140
|
-
return this.productService.findOne(id);
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### @ApiProperty()
|
|
145
|
-
|
|
146
|
-
Document DTO properties:
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
import { ApiProperty } from '@hazeljs/swagger';
|
|
150
|
-
|
|
151
|
-
export class CreateUserDto {
|
|
152
|
-
@ApiProperty({
|
|
153
|
-
description: 'User email address',
|
|
154
|
-
example: 'user@example.com',
|
|
155
|
-
})
|
|
156
|
-
email: string;
|
|
157
|
-
|
|
158
|
-
@ApiProperty({
|
|
159
|
-
description: 'User password',
|
|
160
|
-
minLength: 8,
|
|
161
|
-
example: 'SecurePass123!',
|
|
162
|
-
})
|
|
163
|
-
password: string;
|
|
164
|
-
|
|
165
|
-
@ApiProperty({
|
|
166
|
-
description: 'User full name',
|
|
167
|
-
example: 'John Doe',
|
|
168
|
-
})
|
|
169
|
-
name: string;
|
|
170
|
-
|
|
171
|
-
@ApiProperty({
|
|
172
|
-
description: 'User age',
|
|
173
|
-
minimum: 18,
|
|
174
|
-
maximum: 120,
|
|
175
|
-
example: 25,
|
|
176
|
-
required: false,
|
|
177
|
-
})
|
|
178
|
-
age?: number;
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### @ApiParam()
|
|
183
|
-
|
|
184
|
-
Document path parameters:
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
@Get('/:id')
|
|
188
|
-
@ApiParam({
|
|
189
|
-
name: 'id',
|
|
190
|
-
description: 'User ID',
|
|
191
|
-
type: 'string',
|
|
192
|
-
example: '123',
|
|
193
|
-
})
|
|
194
|
-
findOne(@Param('id') id: string) {
|
|
195
|
-
return this.userService.findOne(id);
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### @ApiQuery()
|
|
200
|
-
|
|
201
|
-
Document query parameters:
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
@Get()
|
|
205
|
-
@ApiQuery({
|
|
206
|
-
name: 'page',
|
|
207
|
-
required: false,
|
|
208
|
-
type: Number,
|
|
209
|
-
description: 'Page number',
|
|
210
|
-
example: 1,
|
|
211
|
-
})
|
|
212
|
-
@ApiQuery({
|
|
213
|
-
name: 'limit',
|
|
214
|
-
required: false,
|
|
215
|
-
type: Number,
|
|
216
|
-
description: 'Items per page',
|
|
217
|
-
example: 10,
|
|
218
|
-
})
|
|
219
|
-
findAll(
|
|
220
|
-
@Query('page') page: number = 1,
|
|
221
|
-
@Query('limit') limit: number = 10
|
|
222
|
-
) {
|
|
223
|
-
return this.userService.findAll(page, limit);
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### @ApiBody()
|
|
228
|
-
|
|
229
|
-
Document request body:
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
@Post()
|
|
233
|
-
@ApiBody({
|
|
234
|
-
description: 'User data',
|
|
235
|
-
type: CreateUserDto,
|
|
236
|
-
examples: {
|
|
237
|
-
user1: {
|
|
238
|
-
summary: 'Example user',
|
|
239
|
-
value: {
|
|
240
|
-
email: 'john@example.com',
|
|
241
|
-
password: 'SecurePass123!',
|
|
242
|
-
name: 'John Doe',
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
})
|
|
247
|
-
create(@Body() createUserDto: CreateUserDto) {
|
|
248
|
-
return this.userService.create(createUserDto);
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### @ApiHeader()
|
|
253
|
-
|
|
254
|
-
Document required headers:
|
|
255
|
-
|
|
256
|
-
```typescript
|
|
257
|
-
@Get('/protected')
|
|
258
|
-
@ApiHeader({
|
|
259
|
-
name: 'Authorization',
|
|
260
|
-
description: 'Bearer token',
|
|
261
|
-
required: true,
|
|
262
|
-
example: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
263
|
-
})
|
|
264
|
-
getProtectedData() {
|
|
265
|
-
return { data: 'protected' };
|
|
266
|
-
}
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### @ApiBearerAuth()
|
|
270
|
-
|
|
271
|
-
Document bearer authentication:
|
|
272
|
-
|
|
273
|
-
```typescript
|
|
274
|
-
@Controller('/admin')
|
|
275
|
-
@ApiBearerAuth()
|
|
276
|
-
export class AdminController {
|
|
277
|
-
@Get('/dashboard')
|
|
278
|
-
getDashboard() {
|
|
279
|
-
return { data: 'admin dashboard' };
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### @ApiSecurity()
|
|
285
|
-
|
|
286
|
-
Document custom security:
|
|
287
29
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
@ApiSecurity('api_key')
|
|
291
|
-
export class ApiController {
|
|
292
|
-
@Get('/data')
|
|
293
|
-
getData() {
|
|
294
|
-
return { data: [] };
|
|
295
|
-
}
|
|
296
|
-
}
|
|
30
|
+
// After you create the app (e.g. where you bootstrap HazelApp):
|
|
31
|
+
SwaggerModule.setRootModule(AppModule);
|
|
297
32
|
```
|
|
298
33
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
### Full Configuration
|
|
34
|
+
### 2. Optional: document metadata, servers, auth, UI CDN, global prefix
|
|
302
35
|
|
|
303
36
|
```typescript
|
|
304
|
-
SwaggerModule.
|
|
305
|
-
// Basic info
|
|
37
|
+
SwaggerModule.configure({
|
|
306
38
|
title: 'My API',
|
|
307
|
-
description: '
|
|
39
|
+
description: 'Production API',
|
|
308
40
|
version: '1.0.0',
|
|
309
|
-
|
|
310
|
-
//
|
|
311
|
-
|
|
312
|
-
{
|
|
313
|
-
url: 'http://localhost:3000',
|
|
314
|
-
description: 'Development server',
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
url: 'https://api.example.com',
|
|
318
|
-
description: 'Production server',
|
|
319
|
-
},
|
|
320
|
-
],
|
|
321
|
-
|
|
322
|
-
// Contact info
|
|
323
|
-
contact: {
|
|
324
|
-
name: 'API Support',
|
|
325
|
-
email: 'support@example.com',
|
|
326
|
-
url: 'https://example.com/support',
|
|
327
|
-
},
|
|
328
|
-
|
|
329
|
-
// License
|
|
330
|
-
license: {
|
|
331
|
-
name: 'Apache-2.0',
|
|
332
|
-
url: 'https://www.apache.org/licenses/LICENSE-2.0',
|
|
41
|
+
servers: [{ url: 'http://localhost:3000', description: 'Local' }],
|
|
42
|
+
globalPrefix: '/api', // match app.setGlobalPrefix('/api') so paths and Swagger UI spec URL align
|
|
43
|
+
securitySchemes: {
|
|
44
|
+
bearer: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
|
|
333
45
|
},
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
termsOfService: 'https://example.com/terms',
|
|
337
|
-
|
|
338
|
-
// External docs
|
|
339
|
-
externalDocs: {
|
|
340
|
-
description: 'Find more info here',
|
|
341
|
-
url: 'https://docs.example.com',
|
|
342
|
-
},
|
|
343
|
-
|
|
344
|
-
// Security schemes
|
|
345
|
-
security: [
|
|
346
|
-
{
|
|
347
|
-
name: 'bearer',
|
|
348
|
-
type: 'http',
|
|
349
|
-
scheme: 'bearer',
|
|
350
|
-
bearerFormat: 'JWT',
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
name: 'api_key',
|
|
354
|
-
type: 'apiKey',
|
|
355
|
-
in: 'header',
|
|
356
|
-
name: 'X-API-Key',
|
|
357
|
-
},
|
|
358
|
-
],
|
|
359
|
-
|
|
360
|
-
// Swagger UI options
|
|
361
|
-
swaggerOptions: {
|
|
362
|
-
persistAuthorization: true,
|
|
363
|
-
displayRequestDuration: true,
|
|
364
|
-
filter: true,
|
|
365
|
-
showExtensions: true,
|
|
366
|
-
},
|
|
367
|
-
|
|
368
|
-
// Path to serve docs
|
|
369
|
-
path: '/api-docs',
|
|
370
|
-
|
|
371
|
-
// Custom CSS
|
|
372
|
-
customCss: '.swagger-ui .topbar { display: none }',
|
|
373
|
-
|
|
374
|
-
// Custom site title
|
|
375
|
-
customSiteTitle: 'My API Documentation',
|
|
46
|
+
security: [{ bearer: [] }],
|
|
47
|
+
swaggerUiCdnBase: 'https://unpkg.com/swagger-ui-dist@5.11.0',
|
|
376
48
|
});
|
|
377
|
-
```
|
|
378
49
|
|
|
379
|
-
|
|
50
|
+
// Replace all options (e.g. in tests):
|
|
51
|
+
SwaggerModule.configure({}, true);
|
|
52
|
+
```
|
|
380
53
|
|
|
381
|
-
###
|
|
54
|
+
### 3. Decorate controllers
|
|
382
55
|
|
|
383
56
|
```typescript
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
security: [
|
|
387
|
-
{
|
|
388
|
-
name: 'bearer',
|
|
389
|
-
type: 'http',
|
|
390
|
-
scheme: 'bearer',
|
|
391
|
-
bearerFormat: 'JWT',
|
|
392
|
-
},
|
|
393
|
-
],
|
|
394
|
-
});
|
|
57
|
+
import { Controller, Get, Post, Body } from '@hazeljs/core';
|
|
58
|
+
import { Swagger, ApiOperation } from '@hazeljs/swagger';
|
|
395
59
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
60
|
+
@Swagger({
|
|
61
|
+
title: 'Users API',
|
|
62
|
+
description: 'User operations',
|
|
63
|
+
version: '1.0.0',
|
|
64
|
+
tags: [{ name: 'users', description: 'Users' }],
|
|
65
|
+
})
|
|
66
|
+
@Controller({ path: '/users' })
|
|
67
|
+
export class UserController {
|
|
400
68
|
@Get()
|
|
401
|
-
|
|
402
|
-
|
|
69
|
+
@ApiOperation({
|
|
70
|
+
summary: 'List users',
|
|
71
|
+
responses: { '200': { description: 'OK' } },
|
|
72
|
+
})
|
|
73
|
+
list() {
|
|
74
|
+
return [];
|
|
403
75
|
}
|
|
404
|
-
}
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
### API Key
|
|
408
76
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
type: 'apiKey',
|
|
416
|
-
in: 'header',
|
|
417
|
-
name: 'X-API-Key',
|
|
77
|
+
@Post()
|
|
78
|
+
@ApiOperation({
|
|
79
|
+
summary: 'Create user',
|
|
80
|
+
requestBody: {
|
|
81
|
+
required: true,
|
|
82
|
+
content: { 'application/json': { schema: { type: 'object' } } },
|
|
418
83
|
},
|
|
419
|
-
|
|
420
|
-
})
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
@Controller('/api')
|
|
424
|
-
@ApiSecurity('api_key')
|
|
425
|
-
export class ApiController {
|
|
426
|
-
@Get()
|
|
427
|
-
getData() {
|
|
428
|
-
return { data: [] };
|
|
84
|
+
responses: { '201': { description: 'Created' } },
|
|
85
|
+
})
|
|
86
|
+
create(@Body() body: unknown) {
|
|
87
|
+
return body;
|
|
429
88
|
}
|
|
430
89
|
}
|
|
431
90
|
```
|
|
432
91
|
|
|
433
|
-
|
|
92
|
+
Routes **without** `@ApiOperation` still appear in the spec when `autoGenerateOperations` is true (default): summaries and placeholder request bodies are inferred from HTTP method and handler name. Set `autoGenerateOperations: false` in `SwaggerModule.configure` or pass `{ autoGenerateOperations: false }` to `SwaggerService.generateSpec` to disable that for programmatic builds.
|
|
434
93
|
|
|
435
|
-
|
|
436
|
-
SwaggerModule.forRoot({
|
|
437
|
-
security: [
|
|
438
|
-
{
|
|
439
|
-
name: 'oauth2',
|
|
440
|
-
type: 'oauth2',
|
|
441
|
-
flows: {
|
|
442
|
-
authorizationCode: {
|
|
443
|
-
authorizationUrl: 'https://example.com/oauth/authorize',
|
|
444
|
-
tokenUrl: 'https://example.com/oauth/token',
|
|
445
|
-
scopes: {
|
|
446
|
-
'read:users': 'Read user information',
|
|
447
|
-
'write:users': 'Modify user information',
|
|
448
|
-
},
|
|
449
|
-
},
|
|
450
|
-
},
|
|
451
|
-
},
|
|
452
|
-
],
|
|
453
|
-
});
|
|
454
|
-
```
|
|
94
|
+
### 4. Open the UI and raw spec
|
|
455
95
|
|
|
456
|
-
|
|
96
|
+
- **Swagger UI:** `GET /swagger/` (or `GET {globalPrefix}/swagger/` if configured)
|
|
97
|
+
- **OpenAPI JSON:** `GET /swagger/spec`
|
|
457
98
|
|
|
458
|
-
|
|
99
|
+
## Programmatic export (CI / codegen)
|
|
459
100
|
|
|
460
101
|
```typescript
|
|
461
|
-
import {
|
|
462
|
-
import {
|
|
463
|
-
|
|
464
|
-
ApiOperation,
|
|
465
|
-
ApiResponse,
|
|
466
|
-
ApiParam,
|
|
467
|
-
ApiBody,
|
|
468
|
-
ApiBearerAuth,
|
|
469
|
-
} from '@hazeljs/swagger';
|
|
470
|
-
|
|
471
|
-
@Controller('/products')
|
|
472
|
-
@ApiTags('Products')
|
|
473
|
-
@ApiBearerAuth()
|
|
474
|
-
export class ProductController {
|
|
475
|
-
@Get()
|
|
476
|
-
@ApiOperation({ summary: 'Get all products' })
|
|
477
|
-
@ApiResponse({
|
|
478
|
-
status: 200,
|
|
479
|
-
description: 'List of products',
|
|
480
|
-
type: [ProductDto],
|
|
481
|
-
})
|
|
482
|
-
findAll() {
|
|
483
|
-
return this.productService.findAll();
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
@Get('/:id')
|
|
487
|
-
@ApiOperation({ summary: 'Get product by ID' })
|
|
488
|
-
@ApiParam({ name: 'id', description: 'Product ID' })
|
|
489
|
-
@ApiResponse({ status: 200, description: 'Product found', type: ProductDto })
|
|
490
|
-
@ApiResponse({ status: 404, description: 'Product not found' })
|
|
491
|
-
findOne(@Param('id') id: string) {
|
|
492
|
-
return this.productService.findOne(id);
|
|
493
|
-
}
|
|
102
|
+
import { createOpenApiDocument } from '@hazeljs/swagger';
|
|
103
|
+
import { AppModule } from './app.module';
|
|
104
|
+
import * as fs from 'node:fs';
|
|
494
105
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
return this.productService.create(createProductDto);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
@Put('/:id')
|
|
505
|
-
@ApiOperation({ summary: 'Update a product' })
|
|
506
|
-
@ApiParam({ name: 'id', description: 'Product ID' })
|
|
507
|
-
@ApiBody({ type: UpdateProductDto })
|
|
508
|
-
@ApiResponse({ status: 200, description: 'Product updated', type: ProductDto })
|
|
509
|
-
@ApiResponse({ status: 404, description: 'Product not found' })
|
|
510
|
-
update(@Param('id') id: string, @Body() updateProductDto: UpdateProductDto) {
|
|
511
|
-
return this.productService.update(id, updateProductDto);
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
@Delete('/:id')
|
|
515
|
-
@ApiOperation({ summary: 'Delete a product' })
|
|
516
|
-
@ApiParam({ name: 'id', description: 'Product ID' })
|
|
517
|
-
@ApiResponse({ status: 200, description: 'Product deleted' })
|
|
518
|
-
@ApiResponse({ status: 404, description: 'Product not found' })
|
|
519
|
-
delete(@Param('id') id: string) {
|
|
520
|
-
return this.productService.delete(id);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
106
|
+
const doc = createOpenApiDocument(AppModule, {
|
|
107
|
+
title: 'My API',
|
|
108
|
+
version: '1.0.0',
|
|
109
|
+
globalPrefix: '/api',
|
|
110
|
+
});
|
|
111
|
+
fs.writeFileSync('openapi.json', JSON.stringify(doc, null, 2));
|
|
523
112
|
```
|
|
524
113
|
|
|
525
|
-
|
|
114
|
+
YAML is not built in; pipe JSON through your preferred YAML tool if needed.
|
|
526
115
|
|
|
527
|
-
|
|
116
|
+
## API reference
|
|
528
117
|
|
|
529
|
-
|
|
530
|
-
|
|
118
|
+
| Export | Role |
|
|
119
|
+
| ----------------------- | --------------------------------------------------------------------------- |
|
|
120
|
+
| `SwaggerModule` | Nest-style module; `setRootModule`, `configure`, `getOptions` |
|
|
121
|
+
| `SwaggerService` | `generateAutoSpec(module, options?)`, `generateSpec(controllers, options?)` |
|
|
122
|
+
| `createOpenApiDocument` | Stateless helper around `generateAutoSpec` |
|
|
123
|
+
| `@Swagger` | Class-level OpenAPI `info` / default `tags` |
|
|
124
|
+
| `@ApiOperation` | Per-route operation (summary, parameters, requestBody, responses) |
|
|
531
125
|
|
|
532
|
-
|
|
533
|
-
const json = JSON.stringify(document, null, 2);
|
|
126
|
+
Default components include `Error` and `ValidationError` schemas. Auto-generated error responses reference `#/components/schemas/Error`.
|
|
534
127
|
|
|
535
|
-
|
|
536
|
-
fs.writeFileSync('./openapi.json', json);
|
|
537
|
-
```
|
|
128
|
+
## Roadmap / not implemented
|
|
538
129
|
|
|
539
|
-
|
|
130
|
+
The following are **not** in this package today (do not rely on READMEs or examples that mention Nestβs full `@nestjs/swagger` surface):
|
|
540
131
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
const document = SwaggerModule.createDocument(app);
|
|
546
|
-
const yamlString = yaml.dump(document);
|
|
547
|
-
|
|
548
|
-
// Save to file
|
|
549
|
-
fs.writeFileSync('./openapi.yaml', yamlString);
|
|
550
|
-
```
|
|
132
|
+
- `@ApiTags`, `@ApiResponse`, `@ApiProperty`, `@ApiParam`, `@ApiQuery`, `@ApiBody`, `@ApiHeader`, `@ApiBearerAuth`, `@ApiSecurity` as separate decorators
|
|
133
|
+
- DTO / class reflection for schemas
|
|
134
|
+
- Built-in YAML export or `SwaggerModule.forRoot` static module factory
|
|
551
135
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
1. **Document All Endpoints** - Add decorators to every route
|
|
555
|
-
2. **Use DTOs** - Define request/response types with `@ApiProperty`
|
|
556
|
-
3. **Add Examples** - Include realistic examples in documentation
|
|
557
|
-
4. **Group by Tags** - Organize endpoints with `@ApiTags`
|
|
558
|
-
5. **Document Errors** - Include all possible error responses
|
|
559
|
-
6. **Security** - Document authentication requirements
|
|
560
|
-
7. **Versioning** - Update version number with API changes
|
|
561
|
-
8. **External Docs** - Link to additional documentation
|
|
136
|
+
Contributions welcome for any of the above.
|
|
562
137
|
|
|
563
138
|
## Testing
|
|
564
139
|
|
|
@@ -566,19 +141,6 @@ fs.writeFileSync('./openapi.yaml', yamlString);
|
|
|
566
141
|
npm test
|
|
567
142
|
```
|
|
568
143
|
|
|
569
|
-
## Contributing
|
|
570
|
-
|
|
571
|
-
Contributions are welcome! Please read our [Contributing Guide](../../CONTRIBUTING.md) for details.
|
|
572
|
-
|
|
573
144
|
## License
|
|
574
145
|
|
|
575
146
|
Apache 2.0 Β© [HazelJS](https://hazeljs.ai)
|
|
576
|
-
|
|
577
|
-
## Links
|
|
578
|
-
|
|
579
|
-
- [Documentation](https://hazeljs.ai/docs/packages/swagger)
|
|
580
|
-
- [OpenAPI Specification](https://swagger.io/specification/)
|
|
581
|
-
- [Swagger UI](https://swagger.io/tools/swagger-ui/)
|
|
582
|
-
- [GitHub](https://github.com/hazel-js/hazeljs)
|
|
583
|
-
- [Issues](https://github.com/hazel-js/hazeljs/issues)
|
|
584
|
-
- [Discord](https://discord.gg/PxNBPzvQk7)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @hazeljs/swagger - Swagger/OpenAPI module for HazelJS
|
|
3
3
|
*/
|
|
4
|
+
import type { Type } from '@hazeljs/core';
|
|
5
|
+
import type { SwaggerBuildOptions, SwaggerSpec } from './swagger.types';
|
|
4
6
|
export { SwaggerModule } from './swagger.module';
|
|
5
|
-
export { SwaggerService
|
|
7
|
+
export { SwaggerService } from './swagger.service';
|
|
6
8
|
export { Swagger, ApiOperation, getSwaggerMetadata, getOperationMetadata, } from './swagger.decorator';
|
|
7
|
-
export type { SwaggerOptions, SwaggerOperation, SwaggerSchema } from './swagger.types';
|
|
8
|
-
|
|
9
|
+
export type { SwaggerOptions, SwaggerOperation, SwaggerSchema, SwaggerSpec, SwaggerServer, SwaggerBuildOptions, AutoSwaggerOptions, SwaggerModuleOptions, } from './swagger.types';
|
|
10
|
+
/** Build an OpenAPI document without serving HTTP (e.g. CI export). */
|
|
11
|
+
export declare function createOpenApiDocument(rootModule: Type<unknown>, options?: SwaggerBuildOptions): SwaggerSpec;
|
|
9
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAExE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,OAAO,EACP,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AAEzB,uEAAuE;AACvE,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,EACzB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,WAAW,CAEb"}
|