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