├── .editorconfig ├── .gitignore ├── .npmignore ├── .prettierrc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── config.template.json ├── gulpfile.js ├── lib └── swagger-express-ts-lib │ ├── package.json │ └── src │ ├── api-model-property.decorator.ts │ ├── api-model.decorator.ts │ ├── api-operation-delete.decorator.ts │ ├── api-operation-get.decorator.ts │ ├── api-operation-patch.decorator.ts │ ├── api-operation-post.decorator.ts │ ├── api-operation-put.decorator.ts │ ├── api-path.decorator.ts │ ├── express.configurator.ts │ ├── i-api-operation-args.base.ts │ ├── i-swagger.ts │ ├── index.ts │ ├── swagger-definition.constant.spec.ts │ ├── swagger-definition.constant.ts │ ├── swagger.builder.ts │ ├── swagger.service.spec.ts │ └── swagger.service.ts ├── package-lock.json ├── package.json ├── src ├── cars │ ├── car.controller.spec.ts │ ├── car.controller.ts │ ├── car.model.ts │ ├── carbulk.controller.ts │ ├── cars.controller.spec.ts │ ├── cars.controller.ts │ ├── cars.service.spec.ts │ ├── cars.service.ts │ └── wheel.model.ts ├── constructors │ └── constructor.model.ts └── index.ts ├── swagger └── index.html ├── test └── mocha.opts ├── tsconfig.dev.lib.json ├── tsconfig.json ├── tsconfig.lib.json ├── tslint.json ├── wiki ├── README.md ├── api-model-property.decorator.md ├── api-model.decorator.md ├── api-operation-delete.decorator.md ├── api-operation-get.decorator.md ├── api-operation-patch.decorator.md ├── api-operation-post.decorator.md ├── api-operation-put.decorator.md ├── api-path.decorator.md ├── configuration.md ├── i-api-body-operation-args-base-parameter.md ├── i-api-operation-args-base-parameter.md ├── i-api-operation-args-base-parameters.md ├── i-api-operation-args-base-response.md ├── i-api-property-body-operation-args-base-parameter.md ├── i-swagger-build-definition-model-property.md ├── i-swagger-build-definition-model.md ├── i-swagger-build-definition.md ├── i-swagger-contact.md ├── i-swagger-external-docs.md ├── i-swagger-info.md ├── i-swagger-license.md ├── i-swagger-security-definition.md ├── img │ ├── logo.png │ └── swagger-ui.png ├── installation.md └── swagger-definition-constant.md └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org/ 4 | 5 | root = true 6 | 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | 11 | [*.{js,ts}] 12 | indent_size = 2 13 | indent_style = space 14 | insert_final_newline = true 15 | trim_trailing_whitespace = true 16 | 17 | [*.md] 18 | trim_trailing_whitespace = false 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | built/ 61 | dist/ 62 | reports/ 63 | config.json 64 | src/**/*.js 65 | example/**/*.js 66 | .idea 67 | .vscode -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | swagger 3 | lib 4 | node_modules 5 | test 6 | wiki 7 | config.* 8 | docs 9 | examples 10 | test 11 | lib-cov 12 | .editorconfig 13 | .jshintignore 14 | .jshintrc 15 | .travis.yml 16 | .prettierrc 17 | tsconfig.* 18 | tslint.* 19 | lcov.info 20 | logo.svg 21 | CHANGELOG.MD 22 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 4, 4 | "semi": true, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | before_install: 5 | - npm i -g npm@latest 6 | - npm i 7 | install: 8 | - npm run tslint 9 | - npm run build 10 | script: 11 | - npm run test 12 | after_success: 13 | - npm run test:coverage 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # [1.0.1](2018-12-4) 4 | 5 | ## Features 6 | 7 | ### example 8 | 9 | Example: 10 | 11 | ```ts 12 | ... 13 | @ApiModelProperty({ 14 | description: 'Id of car', 15 | required: true, 16 | example: ['123456789', '12345'], 17 | }) 18 | id: string; 19 | ... 20 | } 21 | ``` 22 | 23 | or 24 | 25 | ```ts 26 | ... 27 | app.use( 28 | swagger.express({ 29 | ... 30 | models: { 31 | ApiError: { 32 | properties: { 33 | code: { 34 | type: 35 | SwaggerDefinitionConstant.Model.Property 36 | .Type.STRING, 37 | example: ['400'], 38 | }, 39 | message: { 40 | type: 41 | SwaggerDefinitionConstant.Model.Property 42 | .Type.STRING, 43 | example: ['Name of car is required.'], 44 | }, 45 | }, 46 | }, 47 | }, 48 | ... 49 | }, 50 | }) 51 | ); 52 | ... 53 | ``` 54 | 55 | ### body in parameter 56 | 57 | Example: 58 | 59 | ```ts 60 | ... 61 | @ApiOperationPost({ 62 | ... 63 | parameters: { 64 | body: { 65 | description: 'New car', 66 | required: true, 67 | model: 'Car', 68 | }, 69 | }, 70 | ... 71 | }) 72 | ... 73 | ``` 74 | 75 | or 76 | 77 | ```ts 78 | ... 79 | @ApiOperationPost({ 80 | ... 81 | parameters: { 82 | body: { 83 | required: true, 84 | properties: { 85 | name: { type: SwaggerDefinitionConstant.Parameter.Type.STRING, required: true} 86 | } 87 | }, 88 | }, 89 | ... 90 | }) 91 | ... 92 | ``` 93 | 94 | 95 | 96 | # [1.0.0](2018-06-10) 97 | 98 | ## Features 99 | 100 | ### itemType 101 | 102 | Example: 103 | 104 | ```ts 105 | ... 106 | @ApiModelProperty({ 107 | description: "Name of author", 108 | required: true, 109 | itemType: SwaggerDefinitionConstant.Model.Property.Type.STRING 110 | }) 111 | name: string[]; 112 | ... 113 | ``` 114 | 115 | or 116 | 117 | ```ts 118 | ... 119 | app.use( 120 | swagger.express({ 121 | definition: { 122 | ... 123 | models: { 124 | Author: { 125 | name: { 126 | description: "Name of author", 127 | type: SwaggerDefinitionConstant.Model.Property.Type.ARRAY, 128 | itemType: 129 | SwaggerDefinitionConstant.Model.Property.ItemType.STRING, 130 | required: true 131 | } 132 | } 133 | } 134 | } 135 | ... 136 | } 137 | }) 138 | ); 139 | ... 140 | ``` 141 | 142 | 143 | 144 | # [1.0.0-rc.4](2018-05-18) 145 | 146 | ## Features 147 | 148 | ### Add global responses 149 | 150 | Example: 151 | 152 | ```ts 153 | swagger.express({ 154 | definition: { 155 | ... 156 | responses: { 157 | 500: {} 158 | }, 159 | ... 160 | } 161 | }) 162 | ``` 163 | 164 | ## Fixes 165 | 166 | ### Fix ApiModel when arg "name" and class name are equal. 167 | 168 | 169 | 170 | # [1.0.0-rc.3](2018-04-30) 171 | 172 | ## Fixes 173 | 174 | ### Merge models and path 175 | 176 | 177 | 178 | # [1.0.0-rc.2](2018-04-26) 179 | 180 | ## Features 181 | 182 | ### Name 183 | 184 | Merge name when several controllers that point to the same name . 185 | 186 | Example: 187 | 188 | ```ts 189 | @ApiPath({ 190 | path: "/versions", 191 | name: "Version" 192 | }) 193 | ... 194 | export class VersionsController implements interfaces.Controller { 195 | ... 196 | } 197 | 198 | @ApiPath({ 199 | path: "/versions/:id", 200 | name: "Version" 201 | }) 202 | ... 203 | export class VersionController implements interfaces.Controller { 204 | ... 205 | } 206 | ``` 207 | 208 | 209 | 210 | # [1.0.0-rc.1](2018-04-08) 211 | 212 | ## Features 213 | 214 | ### Model 215 | 216 | #### Configuration 217 | 218 | example: 219 | 220 | ```ts 221 | definition : { 222 | ... 223 | models : { 224 | Version : { 225 | properties : { 226 | id : { 227 | type : SwaggerDefinitionConstant.Model.Property.Type.STRING, 228 | required : true 229 | }, 230 | name : { 231 | type : SwaggerDefinitionConstant.Model.Property.Type.STRING, 232 | required : true 233 | }, 234 | description : { 235 | type : SwaggerDefinitionConstant.Model.Property.Type.STRING 236 | }, 237 | version : { 238 | type : SwaggerDefinitionConstant.Model.Property.Type.STRING 239 | }, 240 | author: { 241 | model: "Author" 242 | } 243 | } 244 | }, 245 | Author: { 246 | properties: { 247 | id: { 248 | type: SwaggerDefinitionConstant.Model.Property.Type.STRING, 249 | required : true 250 | }, 251 | name : { 252 | type : SwaggerDefinitionConstant.Model.Property.Type.STRING, 253 | required : true 254 | }, 255 | } 256 | } 257 | }, 258 | ... 259 | } 260 | ``` 261 | 262 | or 263 | 264 | ```ts 265 | @ApiModel({ 266 | description: 'Version description', 267 | name: 'Version', 268 | }) 269 | export class VersionModel { 270 | @ApiModelProperty({ 271 | description: 'Id of version', 272 | required: true, 273 | }) 274 | id: number; 275 | 276 | @ApiModelProperty({ 277 | description: '', 278 | required: true, 279 | }) 280 | name: string; 281 | 282 | @ApiModelProperty({ 283 | description: 'Description of version', 284 | required: true, 285 | }) 286 | description: string; 287 | 288 | @ApiModelProperty({ 289 | description: 'Author of version', 290 | model: 'Author', 291 | }) 292 | author: AuthorModel; 293 | } 294 | ``` 295 | 296 | #### Controller 297 | 298 | example: 299 | 300 | ```ts 301 | @ApiOperationGet( { 302 | ... 303 | responses : { 304 | 200 : { description : "Success" , type : SwaggerDefinitionConstant.Response.Type.ARRAY , model : "Version" } 305 | } , 306 | ... 307 | } ) 308 | ``` 309 | 310 | 311 | 312 | # [1.0.0-beta.1](2018-03-02) 313 | 314 | ## Features 315 | 316 | ### Authentication 317 | 318 | #### Configuration 319 | 320 | example: 321 | 322 | ```ts 323 | app.use( swagger.express( 324 | { 325 | definition : { 326 | ... 327 | securityDefinitions : { 328 | basicAuth : { 329 | type : SwaggerDefinitionConstant.Security.Type.BASIC_AUTHENTICATION 330 | }, 331 | apiKeyHeader : { 332 | type: SwaggerDefinitionConstant.Security.Type.API_KEY, 333 | in: SwaggerDefinitionConstant.Security.In.HEADER, 334 | name: "apiHeader" 335 | } 336 | } 337 | } 338 | } 339 | ) ); 340 | ``` 341 | 342 | #### Basic Authentication 343 | 344 | Example: 345 | 346 | ```ts 347 | ... 348 | @ApiOperationGet( { 349 | ... 350 | security : { 351 | basicAuth : [] 352 | } 353 | } ) 354 | ... 355 | ``` 356 | 357 | #### API Keys 358 | 359 | Example: 360 | 361 | ```ts 362 | ... 363 | @ApiOperationGet( { 364 | ... 365 | security : { 366 | apiKeyHeader : [] 367 | } 368 | } ) 369 | ... 370 | ``` 371 | 372 | ### Operations as deprecated 373 | 374 | Example in path: 375 | 376 | ```ts 377 | ... 378 | @ApiPath( { 379 | ... 380 | deprecated: true 381 | } ) 382 | ... 383 | ``` 384 | 385 | Example in operation: 386 | 387 | ```ts 388 | ... 389 | @ApiOperationGet( { 390 | ... 391 | deprecated: true 392 | } ) 393 | ... 394 | ``` 395 | 396 | 397 | 398 | # [1.0.0-alpha.5](2018-02-18) 399 | 400 | ## Features 401 | 402 | ### externalDocs 403 | 404 | Example: 405 | 406 | ```ts 407 | app.use( 408 | swagger.express({ 409 | definition: { 410 | info: { 411 | title: 'My api', 412 | version: '1.0', 413 | }, 414 | models: { 415 | Version: { 416 | properties: { 417 | id: { 418 | type: 419 | SwaggerDefinitionConstant.Model.Property.Type 420 | .STRING, 421 | required: true, 422 | }, 423 | name: { 424 | type: 425 | SwaggerDefinitionConstant.Model.Property.Type 426 | .STRING, 427 | required: true, 428 | }, 429 | description: { 430 | type: 431 | SwaggerDefinitionConstant.Model.Property.Type 432 | .STRING, 433 | }, 434 | version: { 435 | type: 436 | SwaggerDefinitionConstant.Model.Property.Type 437 | .STRING, 438 | }, 439 | }, 440 | }, 441 | }, 442 | externalDocs: { 443 | url: 'My url', 444 | }, 445 | }, 446 | }) 447 | ); 448 | ``` 449 | 450 | 451 | 452 | # [1.0.0-alpha.4](2018-01-19) 453 | 454 | Add keywords for npm. 455 | 456 | 457 | 458 | # [1.0.0-alpha.3](2018-01-18) 459 | 460 | Complete informations. 461 | 462 | 463 | 464 | # [1.0.0-alpha.2](2018-01-18) 465 | 466 | Complete informations. 467 | 468 | 469 | 470 | # [1.0.0-alpha.1](2018-01-18) 471 | 472 | Complete informations. 473 | 474 | 475 | 476 | # [1.0.0-alpha.0](2018-01-18) 477 | 478 | ## Features 479 | 480 | ### .express(options: ISwaggerExpressOptions) 481 | 482 | Example: 483 | 484 | ```ts 485 | app.use( 486 | swagger.express({ 487 | definition: { 488 | setInfo: { 489 | title: 'My api', 490 | version: '1.0', 491 | }, 492 | models: { 493 | Version: { 494 | properties: { 495 | id: { 496 | type: 497 | SwaggerDefinitionConstant.Definition.Property 498 | .Type.STRING, 499 | required: true, 500 | }, 501 | name: { 502 | type: 503 | SwaggerDefinitionConstant.Definition.Property 504 | .Type.STRING, 505 | required: true, 506 | }, 507 | description: { 508 | type: 509 | SwaggerDefinitionConstant.Definition.Property 510 | .Type.STRING, 511 | }, 512 | version: { 513 | type: 514 | SwaggerDefinitionConstant.Definition.Property 515 | .Type.STRING, 516 | }, 517 | }, 518 | }, 519 | }, 520 | }, 521 | }) 522 | ); 523 | ``` 524 | 525 | ### @ApiPath(args: IApiPathArgs) 526 | 527 | Example: 528 | 529 | ```ts 530 | import { injectable } from 'inversify'; 531 | import 'reflect-metadata'; 532 | import { ApiPath } from 'swagger-express-ts'; 533 | import { controller } from 'inversify-express-utils'; 534 | 535 | @ApiPath({ 536 | path: '/version', 537 | name: 'Version', 538 | }) 539 | @controller('/version') 540 | @injectable() 541 | export class VersionController implements interfaces.Controller { 542 | public static TARGET_NAME: string = 'VersionController'; 543 | } 544 | ``` 545 | 546 | ### @ApiOperationDelete(args: IApiOperationDeleteArgs) 547 | 548 | Example: 549 | 550 | ```ts 551 | import * as express from 'express'; 552 | import { injectable } from 'inversify'; 553 | import { 554 | controller, 555 | interfaces, 556 | requestParam, 557 | httpDelete, 558 | } from 'inversify-express-utils'; 559 | import { 560 | ApiPath, 561 | ApiOperationDelete, 562 | SwaggerDefinitionConstant, 563 | } from 'swagger-express-ts'; 564 | import 'reflect-metadata'; 565 | 566 | @ApiPath({ 567 | path: '/versions', 568 | name: 'Version', 569 | }) 570 | @controller('/versions') 571 | @injectable() 572 | export class VersionController implements interfaces.Controller { 573 | public static TARGET_NAME: string = 'VersionController'; 574 | private data: [any] = [ 575 | { 576 | id: '1', 577 | name: 'Version 1', 578 | description: 'Description Version 1', 579 | version: '1.0.0', 580 | }, 581 | { 582 | id: '2', 583 | name: 'Version 2', 584 | description: 'Description Version 2', 585 | version: '2.0.0', 586 | }, 587 | ]; 588 | 589 | @ApiOperationDelete({ 590 | path: '/{id}', 591 | parameters: { 592 | path: { 593 | id: { 594 | description: 'Id of version', 595 | type: SwaggerDefinitionConstant.Parameter.Type.STRING, 596 | required: true, 597 | }, 598 | }, 599 | }, 600 | responses: { 601 | 200: { description: 'Success' }, 602 | }, 603 | }) 604 | @httpDelete('/:id') 605 | public deleteVersion( 606 | @requestParam('id') id: string, 607 | request: express.Request, 608 | response: express.Response, 609 | next: express.NextFunction 610 | ): void { 611 | this.data.forEach((version: any, index: number) => { 612 | if (version.id === id) { 613 | this.data.splice(index, 1); 614 | return response.status(200).end(); 615 | } 616 | }); 617 | response.status(404).end(); 618 | } 619 | } 620 | ``` 621 | 622 | ### @ApiOperationGet(args: IApiOperationGetArgs) 623 | 624 | Decorate method for getting a resource in your controller. 625 | 626 | Example: 627 | 628 | ```ts 629 | import * as express from 'express'; 630 | import { injectable } from 'inversify'; 631 | import { 632 | controller, 633 | interfaces, 634 | requestParam, 635 | httpGet, 636 | } from 'inversify-express-utils'; 637 | import { 638 | ApiPath, 639 | ApiOperationGet, 640 | SwaggerDefinitionConstant, 641 | } from 'swagger-express-ts'; 642 | import 'reflect-metadata'; 643 | 644 | @ApiPath({ 645 | path: '/versions', 646 | name: 'Version', 647 | }) 648 | @controller('/versions') 649 | @injectable() 650 | export class VersionController implements interfaces.Controller { 651 | public static TARGET_NAME: string = 'VersionController'; 652 | private data: [any] = [ 653 | { 654 | id: '1', 655 | name: 'Version 1', 656 | description: 'Description Version 1', 657 | version: '1.0.0', 658 | }, 659 | { 660 | id: '2', 661 | name: 'Version 2', 662 | description: 'Description Version 2', 663 | version: '2.0.0', 664 | }, 665 | ]; 666 | 667 | @ApiOperationGet({ 668 | description: 'Get version object', 669 | summary: 'Get version', 670 | responses: { 671 | 200: { description: 'Success', isArray: true, model: 'Version' }, 672 | }, 673 | }) 674 | @httpGet('/') 675 | public getVersions( 676 | request: express.Request, 677 | response: express.Response, 678 | next: express.NextFunction 679 | ): void { 680 | response.json(this.data); 681 | } 682 | } 683 | ``` 684 | 685 | ### @ApiOperationPatch(args: IApiOperationPatchArgs) 686 | 687 | Decorate method for updating a field of resource in your controller. 688 | 689 | Example: 690 | 691 | ```ts 692 | import * as express from 'express'; 693 | import { injectable } from 'inversify'; 694 | import { 695 | controller, 696 | interfaces, 697 | requestParam, 698 | httpPatch, 699 | } from 'inversify-express-utils'; 700 | import { 701 | ApiPath, 702 | ApiOperationPatch, 703 | SwaggerDefinitionConstant, 704 | } from 'swagger-express-ts'; 705 | import 'reflect-metadata'; 706 | 707 | @ApiPath({ 708 | path: '/versions', 709 | name: 'Version', 710 | }) 711 | @controller('/versions') 712 | @injectable() 713 | export class VersionController implements interfaces.Controller { 714 | public static TARGET_NAME: string = 'VersionController'; 715 | private data: [any] = [ 716 | { 717 | id: '1', 718 | name: 'Version 1', 719 | description: 'Description Version 1', 720 | version: '1.0.0', 721 | }, 722 | { 723 | id: '2', 724 | name: 'Version 2', 725 | description: 'Description Version 2', 726 | version: '2.0.0', 727 | }, 728 | ]; 729 | 730 | @ApiOperationPatch({ 731 | path: '/{id}/description', 732 | description: 'Patch description in version object', 733 | summary: 'Patch description in version', 734 | parameters: { 735 | path: { 736 | id: { 737 | description: 'Id of version', 738 | type: SwaggerDefinitionConstant.Parameter.Type.STRING, 739 | required: true, 740 | }, 741 | }, 742 | body: { 743 | description: 'New version', 744 | required: true, 745 | model: 'Version', 746 | }, 747 | }, 748 | responses: { 749 | 200: { description: 'Success' }, 750 | 400: { description: 'Parameters fail' }, 751 | 404: { description: 'Version not found' }, 752 | }, 753 | }) 754 | @httpPatch('/:id/description') 755 | public patchVersionDescription( 756 | @requestParam('id') id: string, 757 | request: express.Request, 758 | response: express.Response, 759 | next: express.NextFunction 760 | ): void { 761 | if (!request.body) { 762 | return response.status(400).end(); 763 | } 764 | this.data.forEach((version: any) => { 765 | if (version.id === id) { 766 | version.description = request.body.description; 767 | return response.json(version); 768 | } 769 | }); 770 | response.status(404).end(); 771 | } 772 | } 773 | ``` 774 | 775 | ### @ApiOperationPost(args: IApiOperationPostArgs) 776 | 777 | Decorate method for create a resource in your controller. 778 | 779 | Example: 780 | 781 | ```ts 782 | import * as express from 'express'; 783 | import { injectable } from 'inversify'; 784 | import { 785 | controller, 786 | interfaces, 787 | requestParam, 788 | httpPost, 789 | } from 'inversify-express-utils'; 790 | import { 791 | ApiPath, 792 | ApiOperationPost, 793 | SwaggerDefinitionConstant, 794 | } from 'swagger-express-ts'; 795 | import 'reflect-metadata'; 796 | 797 | @ApiPath({ 798 | path: '/versions', 799 | name: 'Version', 800 | }) 801 | @controller('/versions') 802 | @injectable() 803 | export class VersionController implements interfaces.Controller { 804 | public static TARGET_NAME: string = 'VersionController'; 805 | private data: [any] = [ 806 | { 807 | id: '1', 808 | name: 'Version 1', 809 | description: 'Description Version 1', 810 | version: '1.0.0', 811 | }, 812 | { 813 | id: '2', 814 | name: 'Version 2', 815 | description: 'Description Version 2', 816 | version: '2.0.0', 817 | }, 818 | ]; 819 | 820 | @ApiOperationPost({ 821 | description: 'Post version object', 822 | summary: 'Post new version', 823 | parameters: { 824 | body: { 825 | description: 'New version', 826 | required: true, 827 | model: 'Version', 828 | }, 829 | }, 830 | responses: { 831 | 200: { description: 'Success' }, 832 | 400: { description: 'Parameters fail' }, 833 | }, 834 | }) 835 | @httpPost('/') 836 | public postVersion( 837 | request: express.Request, 838 | response: express.Response, 839 | next: express.NextFunction 840 | ): void { 841 | if (!request.body) { 842 | return response.status(400).end(); 843 | } 844 | this.data.push(request.body); 845 | response.json(request.body); 846 | } 847 | } 848 | ``` 849 | 850 | ### @ApiOperationPut(args: IApiOperationPutArgs) 851 | 852 | Decorate method for updating a resource in your controller. 853 | 854 | Example: 855 | 856 | ```ts 857 | import * as express from 'express'; 858 | import { injectable } from 'inversify'; 859 | import { 860 | controller, 861 | interfaces, 862 | requestParam, 863 | httpPut, 864 | } from 'inversify-express-utils'; 865 | import { 866 | ApiPath, 867 | ApiOperationPut, 868 | SwaggerDefinitionConstant, 869 | } from 'swagger-express-ts'; 870 | import 'reflect-metadata'; 871 | 872 | @ApiPath({ 873 | path: '/versions', 874 | name: 'Version', 875 | }) 876 | @controller('/versions') 877 | @injectable() 878 | export class VersionController implements interfaces.Controller { 879 | public static TARGET_NAME: string = 'VersionController'; 880 | private data: [any] = [ 881 | { 882 | id: '1', 883 | name: 'Version 1', 884 | description: 'Description Version 1', 885 | version: '1.0.0', 886 | }, 887 | { 888 | id: '2', 889 | name: 'Version 2', 890 | description: 'Description Version 2', 891 | version: '2.0.0', 892 | }, 893 | ]; 894 | 895 | @ApiOperationPut({ 896 | path: '/{id}', 897 | parameters: { 898 | path: { 899 | id: { 900 | description: 'Id of version', 901 | type: SwaggerDefinitionConstant.Parameter.Type.STRING, 902 | required: true, 903 | }, 904 | }, 905 | body: { 906 | description: 'Updated version', 907 | model: 'Version', 908 | required: true, 909 | }, 910 | }, 911 | responses: { 912 | 200: { model: 'Version' }, 913 | }, 914 | }) 915 | @httpPut('/:id') 916 | public putVersion( 917 | @requestParam('id') id: string, 918 | request: express.Request, 919 | response: express.Response, 920 | next: express.NextFunction 921 | ): void { 922 | if (!request.body) { 923 | return response.status(400).end(); 924 | } 925 | this.data.forEach((version: any, index: number) => { 926 | if (version.id === id) { 927 | let newVersion = request.body; 928 | version.id = newVersion.id; 929 | version.name = newVersion.name; 930 | version.description = newVersion.description; 931 | version.version = newVersion.version; 932 | this.data[index] = version; 933 | return response.json(version); 934 | } 935 | }); 936 | response.status(404).end(); 937 | } 938 | } 939 | ``` 940 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Olivier LIN-SI-CHENG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](wiki/img/logo.png) 2 | 3 | # swagger-express-ts 4 | Automatically generate and serve swagger.json v2.0. 5 | 6 | ## Getting started 7 | 8 | First, install [swagger-express-ts](https://www.npmjs.com/package/swagger-express-ts). 9 | 10 | ```sh 11 | npm install swagger-express-ts --save 12 | ``` 13 | 14 | and [init tsconfig.json](./wiki/installation.md) 15 | 16 | ## The Basics 17 | 18 | In the examples below, we use [inversify-express-utils](https://www.npmjs.com/package/inversify-express-utils). inversify-express-utils is not required to work with swagger-express-ts. 19 | 20 | ### Step 1: configure express 21 | 22 | ```ts 23 | import * as bodyParser from "body-parser"; 24 | import * as express from "express"; 25 | import "reflect-metadata"; 26 | import { Container } from "inversify"; 27 | import { interfaces, InversifyExpressServer, TYPE } from "inversify-express-utils"; 28 | import { VersionController } from "./version/version.controller"; 29 | import * as swagger from "swagger-express-ts"; 30 | import { SwaggerDefinitionConstant } from "swagger-express-ts"; 31 | const config = require ( "../config.json" ); 32 | 33 | // set up container 34 | const container = new Container (); 35 | 36 | // note that you *must* bind your controllers to Controller 37 | container.bind ( TYPE.Controller ) 38 | .to( VersionController ).inSingletonScope().whenTargetNamed( VersionController.TARGET_NAME ); 39 | 40 | // create server 41 | const server = new InversifyExpressServer ( container ); 42 | 43 | server.setConfig( ( app : any ) => { 44 | app.use( '/api-docs/swagger' , express.static( 'swagger' ) ); 45 | app.use( '/api-docs/swagger/assets' , express.static( 'node_modules/swagger-ui-dist' ) ); 46 | app.use( bodyParser.json() ); 47 | app.use( swagger.express( 48 | { 49 | definition : { 50 | info : { 51 | title : "My api" , 52 | version : "1.0" 53 | } , 54 | externalDocs : { 55 | url : "My url" 56 | } 57 | // Models can be defined here 58 | } 59 | } 60 | ) ); 61 | } ); 62 | 63 | server.setErrorConfig( ( app : any ) => { 64 | app.use( ( err : Error , request : express.Request , response : express.Response , next : express.NextFunction ) => { 65 | console.error( err.stack ); 66 | response.status( 500 ).send( "Something broke!" ); 67 | } ); 68 | } ); 69 | 70 | const app = server.build(); 71 | 72 | app.listen( config.port ); 73 | console.info( "Server is listening on port : " + config.port ); 74 | 75 | ``` 76 | 77 | ### Step 2: Decorate your models 78 | 79 | ```ts 80 | @ApiModel( { 81 | description : "Version description" , 82 | name : "Version" 83 | } ) 84 | export class VersionModel { 85 | 86 | @ApiModelProperty( { 87 | description : "Id of version" , 88 | required : true, 89 | example: ['123456789'] 90 | } ) 91 | id : number; 92 | 93 | @ApiModelProperty( { 94 | description : "" , 95 | required : true 96 | } ) 97 | name : string; 98 | 99 | @ApiModelProperty( { 100 | description : "Description of version" , 101 | required : true 102 | } ) 103 | description : string; 104 | } 105 | ``` 106 | 107 | ### Step 3: Decorate your controllers 108 | 109 | ```ts 110 | @ApiPath({ 111 | path: "/versions", 112 | name: "Version", 113 | security: { basicAuth: [] } 114 | }) 115 | @controller("/versions") 116 | @injectable() 117 | export class VersionController implements interfaces.Controller { 118 | public static TARGET_NAME: string = "VersionController"; 119 | 120 | private data = [{ 121 | id: "1", 122 | name: "Version 1", 123 | description: "Description Version 1", 124 | version: "1.0.0" 125 | }, 126 | { 127 | id: "2", 128 | name: "Version 2", 129 | description: "Description Version 2", 130 | version: "2.0.0" 131 | }]; 132 | 133 | @ApiOperationGet({ 134 | description: "Get versions objects list", 135 | summary: "Get versions list", 136 | responses: { 137 | 200: { description: "Success", type: SwaggerDefinitionConstant.Response.Type.ARRAY, model: "Version" } 138 | }, 139 | security: { 140 | apiKeyHeader: [] 141 | } 142 | }) 143 | @httpGet("/") 144 | public getVersions(request: express.Request, response: express.Response, next: express.NextFunction): void { 145 | response.json(this.data); 146 | } 147 | 148 | @ApiOperationPost({ 149 | description: "Post version object", 150 | summary: "Post new version", 151 | parameters: { 152 | body: { description: "New version", required: true, model: "Version" } 153 | }, 154 | responses: { 155 | 200: { description: "Success" }, 156 | 400: { description: "Parameters fail" } 157 | } 158 | }) 159 | @httpPost("/") 160 | public postVersion(request: express.Request, response: express.Response, next: express.NextFunction): void { 161 | if (!request.body) { 162 | return response.status(400).end(); 163 | } 164 | this.data.push(request.body); 165 | response.json(request.body); 166 | } 167 | 168 | } 169 | ``` 170 | 171 | ### Step 4: Test 172 | 173 | Start your server and test on url : /api-docs/swagger.json 174 | 175 | ## Extra 176 | 177 | ### Serve swagger-ui in your API 178 | 179 | You can serve swagger.json and swagger-ui in your API. 180 | 181 | ```sh 182 | npm install swagger-ui-dist --save 183 | ``` 184 | 185 | Create index.html in new directory "swagger". 186 | 187 | ```html 188 | 189 | 190 | 191 | 192 | 193 | Swagger UI 194 | 196 | 197 | 198 | 199 | 217 | 218 | 219 | 220 | 221 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 |
257 | 258 | 259 | 260 | 282 | 283 | 284 | 285 | 286 | ``` 287 | 288 | Configure your server like that. 289 | 290 | ```ts 291 | app.use( '/api-docs/swagger', express.static( 'swagger' ) ); 292 | app.use( '/api-docs/swagger/assets', express.static( 'node_modules/swagger-ui-dist' ) ); 293 | ``` 294 | 295 | Test it on url "/api-docs/swagger". 296 | 297 | ![](./wiki/img/swagger-ui.png) 298 | 299 | ## Project example 300 | 301 | You can quickly test swagger-express-ts with the project example [example-swagger-express-ts](https://github.com/olivierlsc/example-swagger-express-ts). 302 | 303 | ## Features and API 304 | 305 | - [Installation](./wiki/installation.md) 306 | - [Configuration](./wiki/configuration.md) 307 | - [@ApiModel](./wiki/api-model.decorator.md) 308 | - [@ApiModelProperty](./wiki/api-model-property.decorator.md) 309 | - [@ApiPath](./wiki/api-path.decorator.md) 310 | - [@ApiOperationGet](./wiki/api-operation-get.decorator.md) 311 | - [@ApiOperationPost](./wiki/api-operation-post.decorator.md) 312 | - [@ApiOperationPut](./wiki/api-operation-put.decorator.md) 313 | - [@ApiOperationPatch](./wiki/api-operation-patch.decorator.md) 314 | - [@ApiOperationDelete](./wiki/api-operation-delete.decorator.md) 315 | 316 | ## For any questions, suggestions, or feature requests 317 | 318 | [Please file an issue](https://github.com/olivierlsc/swagger-express-ts/issues)! 319 | 320 | ## Help wanted 321 | 322 | swagger-express-ts wants additional maintainers! To maintain and continue to develop this young library, [Please post in this issue](https://github.com/olivierlsc/swagger-express-ts/issues/34). 323 | -------------------------------------------------------------------------------- /config.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 9200 3 | } 4 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const ts = require('gulp-typescript'); 3 | const sourcemaps = require('gulp-sourcemaps'); 4 | const clean = require('gulp-clean'); 5 | const tslint = require('gulp-tslint'); 6 | 7 | const path = { 8 | src: 'src/**/*.ts', 9 | dist: 'dist', 10 | module: 'node_modules/swagger-express-ts', 11 | lib: { 12 | src: 'lib/swagger-express-ts-lib/src/**/*.ts', 13 | }, 14 | }; 15 | 16 | function cleanAll() { 17 | return gulp 18 | .src(['dist', path.module, '.nyc_output', 'coverage', '*.log*'], { 19 | read: false, 20 | allowEmpty: true, 21 | }) 22 | .pipe(clean()); 23 | } 24 | 25 | function buildLib() { 26 | var tsProjectLib = ts.createProject('tsconfig.lib.json', {}); 27 | return gulp 28 | .src([path.lib.src]) 29 | .pipe(sourcemaps.init({ loadMaps: true })) 30 | .pipe(tsProjectLib()) 31 | .pipe(sourcemaps.write('.')) 32 | .pipe(gulp.dest(path.dist)); 33 | } 34 | 35 | function buildModule() { 36 | var tsProjectModule = ts.createProject('tsconfig.dev.lib.json', {}); 37 | return ( 38 | gulp 39 | .src([path.lib.src]) 40 | .pipe(sourcemaps.init({ loadMaps: true })) 41 | .pipe(tsProjectModule()) 42 | //.on ("error", function (err) { 43 | // process.exit (1); 44 | //}) 45 | .pipe(sourcemaps.write('.')) 46 | .pipe(gulp.dest(path.module)) 47 | ); 48 | } 49 | 50 | function copyFilesInDist() { 51 | return gulp 52 | .src([ 53 | './README.md', 54 | './LICENSE', 55 | './CHANGELOG.md', 56 | './lib/swagger-express-ts-lib/package.json', 57 | ]) 58 | .pipe(gulp.dest(path.dist)); 59 | } 60 | 61 | function tsLint() { 62 | return gulp.src([path.src, path.lib.src]).pipe( 63 | tslint({ 64 | formatter: 'verbose', 65 | fix: true, 66 | }) 67 | ); 68 | // .pipe(tslint.report()) 69 | // .pipe( 70 | // tslintReporter({ 71 | // sort: true, 72 | // filename: 'reports/checkstyle/results.xml', 73 | // severity: 'error', 74 | // }) 75 | // ); 76 | } 77 | gulp.task('tslint', tsLint); 78 | gulp.task('clean', cleanAll); 79 | gulp.task('build:lib', gulp.series('clean', buildLib, copyFilesInDist)); 80 | gulp.task('build', gulp.series('clean', 'tslint', buildModule)); 81 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swagger-express-ts", 3 | "version": "1.1.0", 4 | "description": "Generate and serve swagger.json", 5 | "main": "index.js", 6 | "types": "index.d.ts", 7 | "typings": "index.d.ts", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/olivierlsc/swagger-express-ts.git" 11 | }, 12 | "author": "Olivier LIN-SI-CHENG", 13 | "license": "MIT", 14 | "keywords": [ 15 | "inversify", 16 | "inversifyjs", 17 | "swagger", 18 | "swagger2", 19 | "swagger-ui", 20 | "typescript", 21 | "expressjs", 22 | "express", 23 | "api rest", 24 | "documentation", 25 | "decorator", 26 | "generator", 27 | "swagger.json", 28 | "json", 29 | "rest" 30 | ], 31 | "bugs": { 32 | "url": "https://github.com/olivierlsc/swagger-express-ts/issues" 33 | }, 34 | "homepage": "https://github.com/olivierlsc/swagger-express-ts#readme", 35 | "peerDependencies": { 36 | "@types/body-parser": "^1.19.0", 37 | "@types/compression": "1.7.0", 38 | "@types/express": "^4.17.11", 39 | "@types/helmet": "0.0.48", 40 | "@types/inversify": "^2.0.33", 41 | "@types/lodash": "^4.14.168", 42 | "body-parser": "^1.19.0", 43 | "compression": "^1.7.4", 44 | "express": "^4.17.1", 45 | "helmet": "^4.4.1", 46 | "inversify": "^4.13.0", 47 | "inversify-express-utils": "^4.2.2", 48 | "lodash": "^4.17.21", 49 | "reflect-metadata": "^0.1.13" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/api-model-property.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SwaggerService } from './swagger.service'; 2 | import { IApiOperationArgsBase } from './i-api-operation-args.base'; 3 | 4 | export interface IApiModelPropertyArgs { 5 | /** 6 | * Define if property is required. 7 | * Optional. Default is false. 8 | */ 9 | required?: boolean; 10 | 11 | /** 12 | * Define format of property. Example: SwaggerDefinitionConstant.Definition.Property.Format.INT_64 13 | * Optional. 14 | */ 15 | format?: string; 16 | 17 | /** 18 | * Define type of property. Example: SwaggerDefinitionConstant.Definition.Property.Type.STRING 19 | * Optional. 20 | */ 21 | type?: string; 22 | 23 | /** 24 | * Define description. 25 | * Optional. 26 | */ 27 | description?: string; 28 | 29 | /** 30 | * Define enum; 31 | * Optional. 32 | */ 33 | enum?: string[]; 34 | 35 | /** 36 | * Define model. 37 | * Optional. 38 | */ 39 | model?: string; 40 | 41 | /** 42 | * Define type of item. Example: SwaggerDefinitionConstant.Definition.Property.Type.STRING 43 | * Optional. 44 | */ 45 | itemType?: string; 46 | 47 | /** 48 | * Define example. 49 | */ 50 | example?: any | any[]; 51 | } 52 | 53 | export function ApiModelProperty( 54 | args?: IApiModelPropertyArgs 55 | ): PropertyDecorator { 56 | return (target: any, propertyKey: string | symbol) => { 57 | let propertyType = ''; 58 | 59 | if (typeof args.itemType !== 'undefined' && args.itemType !== null) { 60 | propertyType = args.itemType; 61 | } else { 62 | try { 63 | propertyType = Reflect.getMetadata( 64 | 'design:type', 65 | target, 66 | propertyKey 67 | ).name; 68 | } catch (err) { 69 | if (err.message === "Cannot read property 'name' of undefined") { 70 | throw new Error( 71 | `${err.message}. This usually occours due to a circular reference between models. A possible solution is to set the itemType argument of the @ApiModelProperty to a string that matches the class name of the field type. The field in question is named ${String(propertyKey)}.`); 72 | } else { 73 | throw err; 74 | } 75 | } 76 | } 77 | 78 | SwaggerService.getInstance().addApiModelProperty( 79 | args, 80 | target, 81 | propertyKey, 82 | propertyType 83 | ); 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/api-model.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SwaggerService } from './swagger.service'; 2 | import { IApiOperationArgsBase } from './i-api-operation-args.base'; 3 | 4 | export interface IApiModelArgs { 5 | description?: string; 6 | name?: string; 7 | } 8 | 9 | export function ApiModel(args?: IApiModelArgs): ClassDecorator { 10 | return (target: any) => { 11 | SwaggerService.getInstance().addApiModel(args, target); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/api-operation-delete.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SwaggerService } from './swagger.service'; 2 | import { IApiOperationArgsBase } from './i-api-operation-args.base'; 3 | export interface IApiOperationDeleteArgs extends IApiOperationArgsBase {} 4 | 5 | export function ApiOperationDelete( 6 | args: IApiOperationDeleteArgs 7 | ): MethodDecorator { 8 | return ( 9 | target: any, 10 | propertyKey: string | symbol, 11 | descriptor: PropertyDescriptor 12 | ) => { 13 | SwaggerService.getInstance().addOperationDelete( 14 | args, 15 | target, 16 | propertyKey 17 | ); 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/api-operation-get.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SwaggerService } from './swagger.service'; 2 | import { IApiOperationArgsBase } from './i-api-operation-args.base'; 3 | export interface IApiOperationGetArgs extends IApiOperationArgsBase {} 4 | 5 | export function ApiOperationGet(args: IApiOperationGetArgs): MethodDecorator { 6 | return ( 7 | target: any, 8 | propertyKey: string | symbol, 9 | descriptor: PropertyDescriptor 10 | ) => { 11 | SwaggerService.getInstance().addOperationGet(args, target, propertyKey); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/api-operation-patch.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SwaggerService } from './swagger.service'; 2 | import { IApiOperationArgsBase } from './i-api-operation-args.base'; 3 | export interface IApiOperationPatchArgs extends IApiOperationArgsBase {} 4 | 5 | export function ApiOperationPatch( 6 | args: IApiOperationPatchArgs 7 | ): MethodDecorator { 8 | return ( 9 | target: any, 10 | propertyKey: string | symbol, 11 | descriptor: PropertyDescriptor 12 | ) => { 13 | SwaggerService.getInstance().addOperationPatch( 14 | args, 15 | target, 16 | propertyKey 17 | ); 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/api-operation-post.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SwaggerService } from './swagger.service'; 2 | import { IApiOperationArgsBase } from './i-api-operation-args.base'; 3 | export interface IApiOperationPostArgs extends IApiOperationArgsBase {} 4 | 5 | export function ApiOperationPost(args: IApiOperationPostArgs): MethodDecorator { 6 | return ( 7 | target: any, 8 | propertyKey: string | symbol, 9 | descriptor: PropertyDescriptor 10 | ) => { 11 | SwaggerService.getInstance().addOperationPost( 12 | args, 13 | target, 14 | propertyKey 15 | ); 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/api-operation-put.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SwaggerService } from './swagger.service'; 2 | import { IApiOperationArgsBase } from './i-api-operation-args.base'; 3 | export interface IApiOperationPutArgs extends IApiOperationArgsBase {} 4 | 5 | export function ApiOperationPut(args: IApiOperationPutArgs): MethodDecorator { 6 | return ( 7 | target: any, 8 | propertyKey: string | symbol, 9 | descriptor: PropertyDescriptor 10 | ) => { 11 | SwaggerService.getInstance().addOperationPut(args, target, propertyKey); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/api-path.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SwaggerService } from './swagger.service'; 2 | export interface IApiPathArgs { 3 | path: string; 4 | name: string; 5 | description?: string; 6 | security?: { [key: string]: any[] }; 7 | deprecated?: boolean; 8 | } 9 | export function ApiPath(args: IApiPathArgs): ClassDecorator { 10 | return (target: any) => { 11 | SwaggerService.getInstance().addPath(args, target); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/express.configurator.ts: -------------------------------------------------------------------------------- 1 | import { Router, Request, Response, NextFunction } from 'express'; 2 | import { SwaggerService } from './swagger.service'; 3 | import * as assert from 'assert'; 4 | import { build, ISwaggerBuildDefinition } from './swagger.builder'; 5 | import { ISwagger } from './i-swagger'; 6 | 7 | export interface ISwaggerExpressOptions { 8 | /** 9 | * Path of resource. 10 | * Default is "/api-docs/swagger.json". 11 | */ 12 | path?: string; 13 | 14 | /** 15 | * Swagger Definition. 16 | */ 17 | definition?: ISwaggerBuildDefinition; 18 | } 19 | 20 | export function express(options?: ISwaggerExpressOptions): Router { 21 | let path: string = '/api-docs/swagger.json'; 22 | if (options) { 23 | assert.ok(options.definition, 'Definition is required.'); 24 | if (options.path) { 25 | path = options.path; 26 | } 27 | if (options.definition) { 28 | build(options.definition); 29 | } 30 | } 31 | const router = buildRouter(path); 32 | return router; 33 | } 34 | 35 | function buildRouter(path: string): Router { 36 | const router: Router = Router(); 37 | router.get( 38 | path, 39 | (request: Request, response: Response, next: NextFunction) => { 40 | const data: ISwagger = SwaggerService.getInstance().getData(); 41 | response.json(data); 42 | } 43 | ); 44 | return router; 45 | } 46 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/i-api-operation-args.base.ts: -------------------------------------------------------------------------------- 1 | export interface IApiOperationArgsBaseParameter { 2 | name?: string; // Override [key: string]. Default [key: string]. 3 | description?: string; 4 | type?: string; 5 | required?: boolean; 6 | format?: string; 7 | minimum?: number; 8 | maximum?: number; 9 | default?: number; 10 | deprecated?: boolean; 11 | allowEmptyValue?: boolean; 12 | items?: { 13 | type?: string; 14 | } 15 | } 16 | 17 | export interface IApiPropertyBodyOperationArgsBaseParameter { 18 | type: string; 19 | required?: boolean; 20 | } 21 | 22 | export interface IApiBodyOperationArgsBaseParameter 23 | extends IApiOperationArgsBaseParameter { 24 | properties?: { [key: string]: IApiPropertyBodyOperationArgsBaseParameter }; 25 | model?: string; 26 | } 27 | 28 | export interface IApiOperationArgsBaseResponse { 29 | description?: string; 30 | type?: string; 31 | model?: string; 32 | } 33 | 34 | export interface IApiOperationArgsBaseParameters { 35 | header?: { [key: string]: IApiOperationArgsBaseParameter }; 36 | path?: { [key: string]: IApiOperationArgsBaseParameter }; 37 | query?: { [key: string]: IApiOperationArgsBaseParameter }; 38 | body?: IApiBodyOperationArgsBaseParameter; // use only for POST, PUT and PATCH 39 | formData?: { [key: string]: IApiOperationArgsBaseParameter }; 40 | } 41 | 42 | export interface IApiOperationArgsBase { 43 | /** 44 | * Define description 45 | * Optional. 46 | */ 47 | description?: string; 48 | 49 | /** 50 | * Define summary 51 | * Optional. 52 | */ 53 | summary?: string; 54 | 55 | /** 56 | * Define produces 57 | * Optional. 58 | */ 59 | produces?: string[]; 60 | 61 | /** 62 | * Define consumes 63 | * Optional. 64 | */ 65 | consumes?: string[]; 66 | 67 | /** 68 | * Define tags 69 | * Optional. 70 | */ 71 | tags?: string[]; 72 | 73 | /** 74 | * Define path 75 | * Optional. 76 | */ 77 | path?: string; 78 | 79 | /** 80 | * Define parameters 81 | * Optional. 82 | */ 83 | parameters?: IApiOperationArgsBaseParameters; 84 | 85 | /** 86 | * Define responses 87 | */ 88 | responses: { [key: string]: IApiOperationArgsBaseResponse }; 89 | 90 | /** 91 | * Define security 92 | * Optional. 93 | */ 94 | security?: { [key: string]: any[] }; 95 | 96 | /** 97 | * Define deprecated 98 | * Optional. 99 | */ 100 | deprecated?: boolean; 101 | } 102 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/i-swagger.ts: -------------------------------------------------------------------------------- 1 | import { ISwaggerSecurityDefinition } from './swagger.builder'; 2 | export interface ISwaggerLicense { 3 | name: string; 4 | url?: string; 5 | } 6 | 7 | export interface ISwaggerContact { 8 | name?: string; 9 | url?: string; 10 | email?: string; 11 | } 12 | 13 | export interface ISwaggerInfo { 14 | title: string; 15 | description?: string; 16 | termsOfService?: string; 17 | contact?: ISwaggerContact; 18 | license?: ISwaggerLicense; 19 | version: string; 20 | } 21 | 22 | export interface ISwaggerVariableServer { 23 | enum?: [string]; 24 | default: string; 25 | description?: string; 26 | } 27 | 28 | export interface ISwaggerServer { 29 | url: string; 30 | description?: string; 31 | variables: [ISwaggerVariableServer]; // TODO : Fix it 32 | } 33 | 34 | export interface ISwaggerExternalDocs { 35 | description?: string; 36 | url: string; 37 | } 38 | 39 | export interface ISwaggerOperationParameter { 40 | name: string; 41 | in: string; 42 | type?: string; 43 | items?: { 44 | type?: string; 45 | }; 46 | format?: string; 47 | description?: string; 48 | required?: boolean; 49 | minimum?: number; 50 | maximum?: number; 51 | default?: number; 52 | deprecated?: boolean; 53 | allowEmptyValue?: boolean; 54 | schema?: ISwaggerOperationSchema; 55 | } 56 | 57 | export interface ISwaggerPropertySchemaOperation { 58 | type: string; 59 | } 60 | 61 | export interface ISwaggerOperationSchema { 62 | type?: string; 63 | items?: { $ref: string }; 64 | $ref?: string; 65 | format?: string; 66 | required?: string[]; // Array content name of property 67 | properties?: {[key: string] : ISwaggerPropertySchemaOperation} 68 | } 69 | 70 | export interface ISwaggerOperationSchemaItems { 71 | $ref: string; 72 | } 73 | 74 | export interface ISwaggerOperationResponse { 75 | description?: string; 76 | schema?: ISwaggerOperationSchema; 77 | } 78 | 79 | export interface ISwaggerOperation { 80 | tags?: string[]; 81 | summary?: string; 82 | description?: string; 83 | operationId: string | symbol; 84 | parameters?: ISwaggerOperationParameter[]; 85 | produces?: string[]; 86 | consumes?: string[]; 87 | responses?: { [key: string]: ISwaggerOperationResponse }; 88 | security?: { [key: string]: any[] }[]; 89 | deprecated?: boolean; 90 | } 91 | 92 | export interface ISwaggerTag { 93 | name: string; 94 | description: string; 95 | } 96 | 97 | export interface ISwaggerPath { 98 | get?: ISwaggerOperation; 99 | post?: ISwaggerOperation; 100 | put?: ISwaggerOperation; 101 | patch?: ISwaggerOperation; 102 | delete?: ISwaggerOperation; 103 | } 104 | 105 | export interface ISwaggerDefinitionPropertyItems { 106 | $ref?: string; 107 | type?: string; 108 | } 109 | 110 | export interface ISwaggerDefinitionProperty { 111 | type?: string; // Example : SwaggerDefinition.Definition.Property.Type.INTEGER 112 | format?: string; // Example : SwaggerDefinition.Definition.Property.Format.INT_64 113 | required?: boolean; 114 | description?: string; 115 | enum?: string[]; 116 | items?: ISwaggerDefinitionPropertyItems; 117 | $ref?: string; 118 | example?: any [] 119 | } 120 | 121 | export interface ISwaggerDefinitionXML { 122 | name: string; 123 | } 124 | 125 | export interface ISwaggerDefinition { 126 | type: string; // Example : SwaggerDefinition.Definition.Type.OBJECT 127 | required?: string[]; 128 | properties: { [key: string]: ISwaggerDefinitionProperty }; 129 | xml?: ISwaggerDefinitionXML; 130 | description?: string; 131 | } 132 | 133 | export interface ISwagger { 134 | basePath?: string; 135 | openapi?: string; 136 | info: ISwaggerInfo; 137 | servers?: [ISwaggerServer]; 138 | paths?: { [key: string]: ISwaggerPath }; 139 | host?: string; 140 | swagger: string; 141 | tags?: ISwaggerTag[]; 142 | schemes: string[]; // Example : SwaggerDefinition.Scheme.HTTP 143 | produces: string[]; // Example : SwaggerDefinition.Produce.JSON 144 | consumes: string[]; // Example : SwaggerDefinition.Consume.JSON 145 | definitions: { [key: string]: ISwaggerDefinition }; 146 | externalDocs?: ISwaggerExternalDocs; 147 | securityDefinitions?: { [key: string]: ISwaggerSecurityDefinition }; 148 | } 149 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/index.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | 3 | export { IApiPathArgs, ApiPath } from './api-path.decorator'; 4 | export { 5 | IApiOperationGetArgs, 6 | ApiOperationGet, 7 | } from './api-operation-get.decorator'; 8 | export { 9 | IApiOperationPostArgs, 10 | ApiOperationPost, 11 | } from './api-operation-post.decorator'; 12 | export { 13 | IApiOperationPutArgs, 14 | ApiOperationPut, 15 | } from './api-operation-put.decorator'; 16 | export { 17 | IApiOperationPatchArgs, 18 | ApiOperationPatch, 19 | } from './api-operation-patch.decorator'; 20 | export { 21 | IApiOperationDeleteArgs, 22 | ApiOperationDelete, 23 | } from './api-operation-delete.decorator'; 24 | 25 | export { 26 | IApiModelPropertyArgs, 27 | ApiModelProperty, 28 | } from './api-model-property.decorator'; 29 | export { IApiModelArgs, ApiModel } from './api-model.decorator'; 30 | 31 | export { SwaggerDefinitionConstant } from './swagger-definition.constant'; 32 | export { express, ISwaggerExpressOptions } from './express.configurator'; 33 | export { build } from './swagger.builder'; 34 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/swagger-definition.constant.spec.ts: -------------------------------------------------------------------------------- 1 | import * as chai from 'chai'; 2 | import { SwaggerDefinitionConstant } from '.'; 3 | const expect = chai.expect; 4 | 5 | describe('SwaggerDefinitionConstant', () => { 6 | describe('Produce', () => { 7 | it('expect JSON', () => { 8 | expect(SwaggerDefinitionConstant.Produce.JSON).exist; 9 | }); 10 | it('expect XML', () => { 11 | expect(SwaggerDefinitionConstant.Produce.XML).exist; 12 | }); 13 | it('expect ZIP', () => { 14 | expect(SwaggerDefinitionConstant.Produce.ZIP).exist; 15 | }); 16 | it('expect PDF', () => { 17 | expect(SwaggerDefinitionConstant.Produce.PDF).exist; 18 | }); 19 | it('expect X_WWW_FORM_URLENCODED', () => { 20 | expect(SwaggerDefinitionConstant.Produce.X_WWW_FORM_URLENCODED) 21 | .exist; 22 | }); 23 | it('expect FORM_DATA', () => { 24 | expect(SwaggerDefinitionConstant.Produce.FORM_DATA).exist; 25 | }); 26 | it('expect TEXT_PLAIN', () => { 27 | expect(SwaggerDefinitionConstant.Produce.TEXT_PLAIN).exist; 28 | }); 29 | it('expect TEXT_HTML', () => { 30 | expect(SwaggerDefinitionConstant.Produce.TEXT_HTML).exist; 31 | }); 32 | it('expect PNG', () => { 33 | expect(SwaggerDefinitionConstant.Produce.PNG).exist; 34 | }); 35 | it('expect GIF', () => { 36 | expect(SwaggerDefinitionConstant.Produce.GIF).exist; 37 | }); 38 | it('expect JPEG', () => { 39 | expect(SwaggerDefinitionConstant.Produce.JPEG).exist; 40 | }); 41 | }); 42 | 43 | describe('Scheme', () => { 44 | it('expect HTTP', () => { 45 | expect(SwaggerDefinitionConstant.Scheme.HTTP).exist; 46 | }); 47 | it('expect HTTPS', () => { 48 | expect(SwaggerDefinitionConstant.Scheme.HTTPS).exist; 49 | }); 50 | }); 51 | 52 | describe('Model', () => { 53 | describe('Type', () => { 54 | it('expect OBJECT', () => { 55 | expect(SwaggerDefinitionConstant.Model.Type.OBJECT).exist; 56 | }); 57 | it('expect ARRAY', () => { 58 | expect(SwaggerDefinitionConstant.Model.Type.ARRAY).exist; 59 | }); 60 | }); 61 | describe('Property', () => { 62 | describe('Type', () => { 63 | expectType(SwaggerDefinitionConstant.Model.Property.Type); 64 | }); 65 | describe('Format', () => { 66 | it('expect INT_64', () => { 67 | expect( 68 | SwaggerDefinitionConstant.Model.Property.Format.INT_64 69 | ).exist; 70 | }); 71 | }); 72 | }); 73 | }); 74 | 75 | describe('Parameter', () => { 76 | describe('Type', () => { 77 | expectType(SwaggerDefinitionConstant.Parameter.Type); 78 | }); 79 | describe('In', () => { 80 | it('expect HEADER', () => { 81 | expect(SwaggerDefinitionConstant.Parameter.In.HEADER).exist; 82 | }); 83 | it('expect PATH', () => { 84 | expect(SwaggerDefinitionConstant.Parameter.In.PATH).exist; 85 | }); 86 | it('expect QUERY', () => { 87 | expect(SwaggerDefinitionConstant.Parameter.In.QUERY).exist; 88 | }); 89 | it('expect BODY', () => { 90 | expect(SwaggerDefinitionConstant.Parameter.In.BODY).exist; 91 | }); 92 | it('expect FORM_DATA', () => { 93 | expect(SwaggerDefinitionConstant.Parameter.In.FORM_DATA).exist; 94 | }); 95 | }); 96 | }); 97 | 98 | describe('Response', () => { 99 | describe('Type', () => { 100 | expectType(SwaggerDefinitionConstant.Response.Type); 101 | }); 102 | }); 103 | 104 | describe('Security', () => { 105 | describe('Type', () => { 106 | it('expect BASIC_AUTHENTICATION', () => { 107 | expect( 108 | SwaggerDefinitionConstant.Security.Type.BASIC_AUTHENTICATION 109 | ).exist; 110 | }); 111 | it('expect API_KEY', () => { 112 | expect(SwaggerDefinitionConstant.Security.Type.API_KEY).exist; 113 | }); 114 | }); 115 | describe('In', () => { 116 | it('expect HEADER', () => { 117 | expect(SwaggerDefinitionConstant.Security.In.HEADER).exist; 118 | }); 119 | it('expect QUERY', () => { 120 | expect(SwaggerDefinitionConstant.Security.In.QUERY).exist; 121 | }); 122 | }); 123 | }); 124 | }); 125 | 126 | function expectType(Type: any) { 127 | it('expect STRING', () => { 128 | expect(Type.STRING).exist; 129 | }); 130 | it('expect NUMBER', () => { 131 | expect(Type.NUMBER).exist; 132 | }); 133 | it('expect INTEGER', () => { 134 | expect(Type.INTEGER).exist; 135 | }); 136 | it('expect BOOLEAN', () => { 137 | expect(Type.BOOLEAN).exist; 138 | }); 139 | it('expect ARRAY', () => { 140 | expect(Type.ARRAY).exist; 141 | }); 142 | it('expect OBJECT', () => { 143 | expect(Type.OBJECT).exist; 144 | }); 145 | } 146 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/swagger-definition.constant.ts: -------------------------------------------------------------------------------- 1 | export class SwaggerDefinitionConstant { 2 | public static JSON: string = 'application/json'; 3 | public static XML: string = 'application/xml'; 4 | public static ZIP: string = 'application/zip'; 5 | public static PDF: string = 'application/pdf'; 6 | public static X_WWW_FORM_URLENCODED: string = 'application/x-www-form-urlencoded'; 7 | public static FORM_DATA: string = 'multipart/form-data'; 8 | public static TEXT_PLAIN: string = 'text/plain'; 9 | public static TEXT_HTML: string = 'text/html'; 10 | public static PNG: string = 'image/png'; 11 | public static GIF: string = 'image/gif'; 12 | public static JPEG: string = 'image/jpeg'; 13 | public static STRING: string = 'string'; 14 | public static NUMBER: string = 'number'; 15 | public static INTEGER: string = 'integer'; 16 | public static BOOLEAN: string = 'boolean'; 17 | public static ARRAY: string = 'array'; 18 | public static OBJECT: string = 'object'; 19 | public static QUERY: string = 'query'; 20 | 21 | public static Produce = { 22 | FORM_DATA: SwaggerDefinitionConstant.FORM_DATA, 23 | GIF: SwaggerDefinitionConstant.GIF, 24 | JPEG: SwaggerDefinitionConstant.JPEG, 25 | JSON: SwaggerDefinitionConstant.JSON, 26 | PDF: SwaggerDefinitionConstant.PDF, 27 | PNG: SwaggerDefinitionConstant.PNG, 28 | TEXT_HTML: SwaggerDefinitionConstant.TEXT_HTML, 29 | TEXT_PLAIN: SwaggerDefinitionConstant.TEXT_PLAIN, 30 | XML: SwaggerDefinitionConstant.XML, 31 | X_WWW_FORM_URLENCODED: SwaggerDefinitionConstant.X_WWW_FORM_URLENCODED, 32 | ZIP: SwaggerDefinitionConstant.ZIP, 33 | }; 34 | 35 | public static Scheme = { 36 | HTTP: 'http', 37 | HTTPS: 'https', 38 | }; 39 | 40 | public static Consume = { 41 | JSON: SwaggerDefinitionConstant.JSON, 42 | XML: SwaggerDefinitionConstant.XML, 43 | }; 44 | 45 | public static Model = { 46 | Property: { 47 | Format: { 48 | INT_64: 'int64', 49 | INT_32: 'int32', 50 | FLOAT: 'float', 51 | DOUBLE: 'double', 52 | BYTE: 'byte', 53 | BINARY: 'binary', 54 | DATE: 'date', 55 | DATE_TIME: 'date-time', 56 | PASSWORD: 'password' 57 | }, 58 | ItemType: { 59 | BOOLEAN: SwaggerDefinitionConstant.BOOLEAN, 60 | INTEGER: SwaggerDefinitionConstant.INTEGER, 61 | NUMBER: SwaggerDefinitionConstant.NUMBER, 62 | STRING: SwaggerDefinitionConstant.STRING, 63 | }, 64 | Type: { 65 | ARRAY: SwaggerDefinitionConstant.ARRAY, 66 | BOOLEAN: SwaggerDefinitionConstant.BOOLEAN, 67 | INTEGER: SwaggerDefinitionConstant.INTEGER, 68 | NUMBER: SwaggerDefinitionConstant.NUMBER, 69 | OBJECT: SwaggerDefinitionConstant.OBJECT, 70 | STRING: SwaggerDefinitionConstant.STRING, 71 | }, 72 | }, 73 | Type: { 74 | OBJECT: SwaggerDefinitionConstant.OBJECT, 75 | ARRAY: SwaggerDefinitionConstant.ARRAY, 76 | }, 77 | }; 78 | 79 | public static Parameter = { 80 | In: { 81 | HEADER: 'header', 82 | BODY: 'body', 83 | FORM_DATA: 'formData', 84 | PATH: 'path', 85 | QUERY: SwaggerDefinitionConstant.QUERY, 86 | }, 87 | Type: { 88 | ARRAY: SwaggerDefinitionConstant.ARRAY, 89 | BOOLEAN: SwaggerDefinitionConstant.BOOLEAN, 90 | INTEGER: SwaggerDefinitionConstant.INTEGER, 91 | NUMBER: SwaggerDefinitionConstant.NUMBER, 92 | OBJECT: SwaggerDefinitionConstant.OBJECT, 93 | STRING: SwaggerDefinitionConstant.STRING, 94 | }, 95 | }; 96 | 97 | public static Response = { 98 | Type: { 99 | ARRAY: SwaggerDefinitionConstant.ARRAY, 100 | BOOLEAN: SwaggerDefinitionConstant.BOOLEAN, 101 | INTEGER: SwaggerDefinitionConstant.INTEGER, 102 | NUMBER: SwaggerDefinitionConstant.NUMBER, 103 | OBJECT: SwaggerDefinitionConstant.OBJECT, 104 | STRING: SwaggerDefinitionConstant.STRING, 105 | }, 106 | }; 107 | 108 | public static Security = { 109 | In: { 110 | HEADER: 'header', 111 | QUERY: SwaggerDefinitionConstant.QUERY, 112 | }, 113 | Type: { 114 | API_KEY: 'apiKey', 115 | BASIC_AUTHENTICATION: 'basic', 116 | }, 117 | }; 118 | } 119 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/swagger.builder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ISwaggerInfo, 3 | ISwaggerDefinition, 4 | ISwaggerDefinitionProperty, 5 | ISwaggerExternalDocs, 6 | ISwaggerOperationResponse, 7 | } from './i-swagger'; 8 | import * as assert from 'assert'; 9 | import { SwaggerService } from './swagger.service'; 10 | import { SwaggerDefinitionConstant } from './swagger-definition.constant'; 11 | import { 12 | IApiOperationArgsBaseParameter, 13 | IApiOperationArgsBaseResponse, 14 | } from './i-api-operation-args.base'; 15 | 16 | export interface ISwaggerBuildDefinitionModelPropertyType { 17 | type?: string | ISwaggerBuildDefinitionModelPropertyType; 18 | } 19 | 20 | export interface ISwaggerBuildDefinitionModelProperty { 21 | /** 22 | * Define type of property. Example: SwaggerDefinitionConstant.Definition.Property.Type.STRING 23 | * Optional. 24 | */ 25 | type?: string; 26 | 27 | /** 28 | * Define format of property. Example: SwaggerDefinitionConstant.Definition.Property.Format.INT_64 29 | * Optional. 30 | */ 31 | format?: string; 32 | 33 | /** 34 | * Define if property is required. 35 | * Optional. Default is false. 36 | */ 37 | required?: boolean; 38 | 39 | /** 40 | * Define model. 41 | * Optional. 42 | */ 43 | model?: string; 44 | 45 | /** 46 | * Define enum; 47 | * Optional. 48 | */ 49 | enum?: string[]; 50 | 51 | /** 52 | * Define description. 53 | * Optional. 54 | */ 55 | description?: string; 56 | 57 | /** 58 | * Define type of item. Example: SwaggerDefinitionConstant.Definition.Property.Type.STRING 59 | * Optional. 60 | */ 61 | itemType?: string; 62 | 63 | /** 64 | * Define example. 65 | */ 66 | example?: any[]; 67 | } 68 | 69 | export interface ISwaggerBuildDefinitionModel { 70 | /** 71 | * Define description. 72 | */ 73 | description?: string; 74 | 75 | /** 76 | * Define all properties of model. 77 | */ 78 | properties: { [key: string]: ISwaggerBuildDefinitionModelProperty }; 79 | } 80 | 81 | export interface ISwaggerSecurityDefinition { 82 | /** 83 | * Define type of security. 84 | */ 85 | type: string; 86 | 87 | /** 88 | * Define where security set. 89 | * Optional. 90 | */ 91 | in?: string; 92 | 93 | /** 94 | * Define name of security. 95 | * Optional. 96 | */ 97 | name?: string; 98 | } 99 | 100 | export interface ISwaggerBuildDefinition { 101 | /** 102 | * Base URL for all API. 103 | * Optional. Default is "/". 104 | */ 105 | basePath?: string; 106 | 107 | /** 108 | * Version Open API 109 | * Optional. 110 | */ 111 | openapi?: string; 112 | 113 | /** 114 | * Metadata. 115 | */ 116 | info: ISwaggerInfo; 117 | 118 | /** 119 | * Define the MIME types supported by the API for consumes. The root-level definition can be overridden in individual operations. 120 | * Optional. Default is SwaggerDefinition.Consume.JSON = "application/json". 121 | */ 122 | consumes?: string[]; 123 | 124 | /** 125 | * Define the MIME types supported by the API for produces. The root-level definition can be overridden in individual operations. 126 | * Optional. Default is SwaggerDefinition.Produce.JSON = "application/json". 127 | */ 128 | produces?: string[]; 129 | 130 | /** 131 | * Define schemes. 132 | * Optional. Default is SwaggerDefinition.Scheme.HTTP = "http". 133 | */ 134 | schemes?: string[]; 135 | 136 | /** 137 | * Define host. 138 | * Optional. 139 | */ 140 | host?: string; 141 | 142 | /** 143 | * Define All Definitions. 144 | * Optional. 145 | */ 146 | models?: { [key: string]: ISwaggerBuildDefinitionModel }; 147 | 148 | /** 149 | * Define external doc 150 | * Optional. 151 | */ 152 | externalDocs?: ISwaggerExternalDocs; 153 | 154 | /** 155 | * Define security definitions list. 156 | * Optional. 157 | */ 158 | securityDefinitions?: { [key: string]: ISwaggerSecurityDefinition }; 159 | 160 | /** 161 | * Define global responses. 162 | * Optional. 163 | */ 164 | responses?: { [key: string]: IApiOperationArgsBaseResponse }; 165 | } 166 | 167 | export function build(buildDefinition: ISwaggerBuildDefinition): void { 168 | assert.ok(buildDefinition, 'Definition are required.'); 169 | assert.ok( 170 | buildDefinition.info, 171 | 'Informations are required. Base is { title: "Title of my API", version: "1.0.0"}' 172 | ); 173 | if (buildDefinition.basePath) { 174 | SwaggerService.getInstance().setBasePath(buildDefinition.basePath); 175 | } 176 | if (buildDefinition.openapi) { 177 | SwaggerService.getInstance().setOpenapi(buildDefinition.openapi); 178 | } 179 | if (buildDefinition.info) { 180 | SwaggerService.getInstance().setInfo(buildDefinition.info); 181 | } 182 | if (buildDefinition.schemes) { 183 | SwaggerService.getInstance().setSchemes(buildDefinition.schemes); 184 | } 185 | if (buildDefinition.produces) { 186 | SwaggerService.getInstance().setProduces(buildDefinition.produces); 187 | } 188 | if (buildDefinition.consumes) { 189 | SwaggerService.getInstance().setConsumes(buildDefinition.consumes); 190 | } 191 | if (buildDefinition.host) { 192 | SwaggerService.getInstance().setHost(buildDefinition.host); 193 | } 194 | if (buildDefinition.externalDocs) { 195 | SwaggerService.getInstance().setExternalDocs( 196 | buildDefinition.externalDocs 197 | ); 198 | } 199 | if (buildDefinition.securityDefinitions) { 200 | SwaggerService.getInstance().addSecurityDefinitions( 201 | buildDefinition.securityDefinitions 202 | ); 203 | } 204 | if (buildDefinition.models) { 205 | SwaggerService.getInstance().setDefinitions(buildDefinition.models); 206 | } 207 | if (buildDefinition.responses) { 208 | SwaggerService.getInstance().setGlobalResponses( 209 | buildDefinition.responses 210 | ); 211 | } 212 | SwaggerService.getInstance().buildSwagger(); 213 | } 214 | -------------------------------------------------------------------------------- /lib/swagger-express-ts-lib/src/swagger.service.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as _ from 'lodash'; 3 | import { IApiModelArgs } from '.'; 4 | import { IApiModelPropertyArgs } from './api-model-property.decorator'; 5 | import { IApiOperationGetArgs } from './api-operation-get.decorator'; 6 | import { IApiOperationPostArgs } from './api-operation-post.decorator'; 7 | import { IApiPathArgs } from './api-path.decorator'; 8 | import { 9 | IApiBodyOperationArgsBaseParameter, 10 | IApiOperationArgsBase, 11 | IApiOperationArgsBaseParameter, 12 | IApiOperationArgsBaseResponse, 13 | } from './i-api-operation-args.base'; 14 | import { 15 | ISwagger, 16 | ISwaggerDefinition, 17 | ISwaggerDefinitionProperty, 18 | ISwaggerDefinitionPropertyItems, 19 | ISwaggerExternalDocs, 20 | ISwaggerInfo, 21 | ISwaggerOperation, 22 | ISwaggerOperationParameter, 23 | ISwaggerOperationResponse, 24 | ISwaggerOperationSchema, 25 | ISwaggerOperationSchemaItems, 26 | ISwaggerPath, 27 | ISwaggerPropertySchemaOperation, 28 | ISwaggerTag, 29 | } from './i-swagger'; 30 | import { SwaggerDefinitionConstant } from './swagger-definition.constant'; 31 | import { 32 | ISwaggerBuildDefinitionModel, 33 | ISwaggerBuildDefinitionModelProperty, 34 | ISwaggerSecurityDefinition, 35 | } from './swagger.builder'; 36 | 37 | interface IPath { 38 | path: string; 39 | get?: ISwaggerOperation; 40 | post?: ISwaggerOperation; 41 | put?: ISwaggerOperation; 42 | patch?: ISwaggerOperation; 43 | delete?: ISwaggerOperation; 44 | } 45 | 46 | interface IController { 47 | path?: string; 48 | paths?: { [key: string]: IPath }; 49 | name?: string; 50 | description?: string; 51 | security?: { [key: string]: any[] }; 52 | deprecated?: boolean; 53 | } 54 | 55 | export class SwaggerService { 56 | public static getInstance(): SwaggerService { 57 | if (!SwaggerService.instance) { 58 | const newSwaggerService: SwaggerService = new SwaggerService(); 59 | newSwaggerService.initData(); 60 | SwaggerService.instance = newSwaggerService; 61 | } 62 | return SwaggerService.instance; 63 | } 64 | private static instance: SwaggerService; 65 | private controllerMap: { [key: string]: IController } = {}; 66 | private data: ISwagger; 67 | private modelsMap: { [key: string]: ISwaggerBuildDefinitionModel } = {}; 68 | private globalResponses: { [key: string]: IApiOperationArgsBaseResponse }; 69 | 70 | public resetData(): void { 71 | this.controllerMap = {}; 72 | this.initData(); 73 | } 74 | 75 | public getData(): ISwagger { 76 | return _.cloneDeep(this.data); 77 | } 78 | 79 | public setBasePath(basePath: string): void { 80 | this.data.basePath = basePath; 81 | } 82 | 83 | public setOpenapi(openapi: string): void { 84 | this.data.openapi = openapi; 85 | } 86 | 87 | public setInfo(info: ISwaggerInfo): void { 88 | this.data.info = info; 89 | } 90 | 91 | public setSchemes(schemes: string[]): void { 92 | this.data.schemes = schemes; 93 | } 94 | 95 | public setProduces(produces: string[]): void { 96 | this.data.produces = produces; 97 | } 98 | 99 | public setConsumes(consumes: string[]): void { 100 | this.data.consumes = consumes; 101 | } 102 | 103 | public setHost(host: string): void { 104 | this.data.host = host; 105 | } 106 | 107 | public setDefinitions(models: { 108 | [key: string]: ISwaggerBuildDefinitionModel; 109 | }): void { 110 | const definitions: { [key: string]: ISwaggerDefinition } = {}; 111 | for (const modelIndex in models) { 112 | const model: ISwaggerBuildDefinitionModel = models[modelIndex]; 113 | const newDefinition: ISwaggerDefinition = { 114 | type: SwaggerDefinitionConstant.Model.Type.OBJECT, 115 | properties: {}, 116 | required: [], 117 | }; 118 | if (model.description) { 119 | newDefinition.description = model.description; 120 | } 121 | for (const propertyIndex in model.properties) { 122 | const property: ISwaggerBuildDefinitionModelProperty = 123 | model.properties[propertyIndex]; 124 | const newProperty: ISwaggerDefinitionProperty = { 125 | type: property.type, 126 | }; 127 | newProperty.format = property.format; 128 | newProperty.description = property.description; 129 | newProperty.enum = property.enum; 130 | newProperty.example = property.example; 131 | if (property.itemType) { 132 | newProperty.items = { 133 | type: property.itemType, 134 | } as ISwaggerDefinitionPropertyItems; 135 | } 136 | if (property.model) { 137 | if ( 138 | _.isEqual( 139 | SwaggerDefinitionConstant.Model.Property.Type.ARRAY, 140 | property.type 141 | ) 142 | ) { 143 | newProperty.items = { 144 | $ref: this.buildRef(property.model), 145 | } as ISwaggerDefinitionPropertyItems; 146 | } else { 147 | newProperty.$ref = this.buildRef(property.model); 148 | } 149 | } 150 | if (property.required) { 151 | newDefinition.required.push(propertyIndex); 152 | } 153 | newDefinition.properties[propertyIndex] = newProperty; 154 | } 155 | definitions[modelIndex] = newDefinition; 156 | } 157 | this.data.definitions = _.mergeWith(this.data.definitions, definitions); 158 | } 159 | 160 | public setExternalDocs(externalDocs: ISwaggerExternalDocs): void { 161 | this.data.externalDocs = externalDocs; 162 | } 163 | 164 | public setGlobalResponses(globalResponses: { 165 | [key: string]: IApiOperationArgsBaseResponse; 166 | }): void { 167 | this.globalResponses = this.buildOperationResponses(globalResponses); 168 | } 169 | 170 | public addPath(args: IApiPathArgs, target: any): void { 171 | let currentController: IController = { 172 | path: args.path, 173 | name: args.name, 174 | paths: {}, 175 | }; 176 | for (const controllerIndex in this.controllerMap) { 177 | const controller: IController = this.controllerMap[controllerIndex]; 178 | if (controllerIndex === target.name) { 179 | currentController = controller; 180 | currentController.path = args.path; 181 | currentController.name = args.name; 182 | currentController.description = args.description; 183 | currentController.security = args.security; 184 | currentController.deprecated = args.deprecated; 185 | } 186 | } 187 | this.controllerMap[target.name] = _.mergeWith( 188 | this.controllerMap[target.name], 189 | currentController 190 | ); 191 | } 192 | 193 | public addOperationGet( 194 | args: IApiOperationGetArgs, 195 | target: any, 196 | propertyKey: string | symbol 197 | ): void { 198 | assert.ok(args, 'Args are required.'); 199 | assert.ok(args.responses, 'Responses are required.'); 200 | if (args.parameters) { 201 | assert.ok(!args.parameters.body, 'Parameter body is not required.'); 202 | } 203 | this.addOperation('get', args, target, propertyKey); 204 | } 205 | 206 | public addOperationPost( 207 | args: IApiOperationPostArgs, 208 | target: any, 209 | propertyKey: string | symbol 210 | ): void { 211 | assert.ok(args, 'Args are required.'); 212 | assert.ok(args.parameters, 'Parameters are required.'); 213 | assert.ok(args.responses, 'Responses are required.'); 214 | this.addOperation('post', args, target, propertyKey); 215 | } 216 | 217 | public addOperationPut( 218 | args: IApiOperationPostArgs, 219 | target: any, 220 | propertyKey: string | symbol 221 | ): void { 222 | assert.ok(args, 'Args are required.'); 223 | assert.ok(args.parameters, 'Parameters are required.'); 224 | assert.ok(args.responses, 'Responses are required.'); 225 | this.addOperation('put', args, target, propertyKey); 226 | } 227 | 228 | public addOperationPatch( 229 | args: IApiOperationPostArgs, 230 | target: any, 231 | propertyKey: string | symbol 232 | ): void { 233 | assert.ok(args, 'Args are required.'); 234 | assert.ok(args.parameters, 'Parameters are required.'); 235 | assert.ok(args.responses, 'Responses are required.'); 236 | this.addOperation('patch', args, target, propertyKey); 237 | } 238 | 239 | public addOperationDelete( 240 | args: IApiOperationPostArgs, 241 | target: any, 242 | propertyKey: string | symbol 243 | ): void { 244 | assert.ok(args, 'Args are required.'); 245 | assert.ok(args.parameters, 'Parameters are required.'); 246 | assert.ok(!args.parameters.body, 'Parameter body is not required.'); 247 | assert.ok(args.responses, 'Responses are required.'); 248 | this.addOperation('delete', args, target, propertyKey); 249 | } 250 | 251 | public addSecurityDefinitions(securityDefinitions: { 252 | [key: string]: ISwaggerSecurityDefinition; 253 | }): void { 254 | this.data.securityDefinitions = securityDefinitions; 255 | } 256 | 257 | public buildSwagger(): void { 258 | const data: ISwagger = _.cloneDeep(this.data); 259 | for (const controllerIndex in this.controllerMap) { 260 | const controller: IController = this.controllerMap[controllerIndex]; 261 | if (_.toArray(controller.paths).length > 0) { 262 | for (const pathIndex in controller.paths) { 263 | const path: IPath = controller.paths[pathIndex]; 264 | const swaggerPath: ISwaggerPath = {}; 265 | if (path.get) { 266 | swaggerPath.get = this.buildSwaggerOperation( 267 | path.get, 268 | controller 269 | ); 270 | } 271 | if (path.post) { 272 | swaggerPath.post = this.buildSwaggerOperation( 273 | path.post, 274 | controller 275 | ); 276 | } 277 | if (path.put) { 278 | swaggerPath.put = this.buildSwaggerOperation( 279 | path.put, 280 | controller 281 | ); 282 | } 283 | if (path.patch) { 284 | swaggerPath.patch = this.buildSwaggerOperation( 285 | path.patch, 286 | controller 287 | ); 288 | } 289 | if (path.delete) { 290 | swaggerPath.delete = this.buildSwaggerOperation( 291 | path.delete, 292 | controller 293 | ); 294 | } 295 | if (path.path && path.path.length > 0) { 296 | data.paths[controller.path.concat(path.path)] = {...data.paths[controller.path.concat(path.path)],...swaggerPath}; 297 | } else { 298 | data.paths[controller.path] = swaggerPath; 299 | } 300 | } 301 | } else { 302 | const swaggerPath: ISwaggerPath = {}; 303 | data.paths[controller.path] = swaggerPath; 304 | } 305 | 306 | if (!_.find(data.tags, (tag: ISwaggerTag) => tag.name === _.upperFirst(controller.name))) { 307 | data.tags.push({ 308 | name: _.upperFirst(controller.name), 309 | description: controller.description, 310 | } as ISwaggerTag); 311 | } 312 | } 313 | this.data = data; 314 | } 315 | 316 | public addApiModelProperty( 317 | args: IApiModelPropertyArgs, 318 | target: any, 319 | propertyKey: string | symbol, 320 | propertyType: string 321 | ) { 322 | const definitionKey = target.constructor.name; 323 | let swaggerBuildDefinitionModel: ISwaggerBuildDefinitionModel = this 324 | .modelsMap[definitionKey]; 325 | if (!swaggerBuildDefinitionModel) { 326 | swaggerBuildDefinitionModel = { 327 | properties: {}, 328 | }; 329 | this.modelsMap[definitionKey] = swaggerBuildDefinitionModel; 330 | } 331 | 332 | const swaggerBuildDefinitionModelProperty: ISwaggerBuildDefinitionModelProperty = { 333 | type: _.lowerCase(propertyType), 334 | }; 335 | if (args) { 336 | swaggerBuildDefinitionModelProperty.required = args.required; 337 | swaggerBuildDefinitionModelProperty.description = args.description; 338 | swaggerBuildDefinitionModelProperty.enum = args.enum; 339 | swaggerBuildDefinitionModelProperty.itemType = args.itemType; 340 | swaggerBuildDefinitionModelProperty.example = args.example; 341 | swaggerBuildDefinitionModelProperty.format = args.format; 342 | if (args.model) { 343 | swaggerBuildDefinitionModelProperty.model = args.model; 344 | if (!_.isEqual('Array', propertyType)) { 345 | swaggerBuildDefinitionModelProperty.type = undefined; 346 | } 347 | } 348 | if (args.type) { 349 | swaggerBuildDefinitionModelProperty.type = args.type; 350 | } 351 | } 352 | swaggerBuildDefinitionModel.properties[ 353 | propertyKey.toString() 354 | ] = swaggerBuildDefinitionModelProperty; 355 | this.setDefinitions(this.modelsMap); 356 | } 357 | 358 | public addApiModel(args: IApiModelArgs, target: any): any { 359 | const definitionKey = target.name; 360 | let swaggerBuildDefinitionModel: ISwaggerBuildDefinitionModel = this 361 | .modelsMap[definitionKey]; 362 | if (!swaggerBuildDefinitionModel) { 363 | swaggerBuildDefinitionModel = { 364 | properties: {}, 365 | }; 366 | this.modelsMap[definitionKey] = swaggerBuildDefinitionModel; 367 | } 368 | if (args) { 369 | swaggerBuildDefinitionModel.description = args.description; 370 | if (args.name) { 371 | const name: string = _.upperFirst(args.name); 372 | this.modelsMap[name] = _.cloneDeep( 373 | this.modelsMap[definitionKey] 374 | ); 375 | if (!_.isEqual(name, definitionKey)) { 376 | delete this.modelsMap[definitionKey]; 377 | delete this.data.definitions[definitionKey]; 378 | } 379 | } 380 | } 381 | this.setDefinitions(this.modelsMap); 382 | } 383 | 384 | private initData(): void { 385 | this.data = { 386 | basePath: '/', 387 | info: { 388 | title: '', 389 | version: '', 390 | } as ISwaggerInfo, 391 | paths: {}, 392 | tags: [], 393 | schemes: [SwaggerDefinitionConstant.Scheme.HTTP], 394 | produces: [SwaggerDefinitionConstant.Produce.JSON], 395 | consumes: [SwaggerDefinitionConstant.Consume.JSON], 396 | definitions: {}, 397 | swagger: '2.0', 398 | }; 399 | } 400 | 401 | private addOperation( 402 | operation: string, 403 | args: IApiOperationArgsBase, 404 | target: any, 405 | propertyKey: string | symbol 406 | ): void { 407 | let currentController: IController = { 408 | paths: {}, 409 | }; 410 | for (const index in this.controllerMap) { 411 | const controller = this.controllerMap[index]; 412 | if (index === target.constructor.name) { 413 | currentController = controller; 414 | } 415 | } 416 | 417 | let currentPath: IPath; 418 | if (args.path && args.path.length > 0) { 419 | if (!currentController.paths[args.path]) { 420 | currentController.paths[args.path] = {} as IPath; 421 | } 422 | currentPath = currentController.paths[args.path]; 423 | currentPath.path = args.path; 424 | } else { 425 | if (!currentController.paths['/']) { 426 | currentController.paths['/'] = {} as IPath; 427 | } 428 | currentPath = currentController.paths['/']; 429 | } 430 | 431 | if ('get' === operation) { 432 | currentPath.get = this.buildOperation(args, target, propertyKey); 433 | } 434 | 435 | if ('post' === operation) { 436 | currentPath.post = this.buildOperation(args, target, propertyKey); 437 | } 438 | 439 | if ('put' === operation) { 440 | currentPath.put = this.buildOperation(args, target, propertyKey); 441 | } 442 | 443 | if ('patch' === operation) { 444 | currentPath.patch = this.buildOperation(args, target, propertyKey); 445 | } 446 | 447 | if ('delete' === operation) { 448 | currentPath.delete = this.buildOperation(args, target, propertyKey); 449 | } 450 | 451 | this.controllerMap[target.constructor.name] = currentController; 452 | } 453 | 454 | private buildOperation( 455 | args: IApiOperationArgsBase, 456 | target: any, 457 | propertyKey: string | symbol 458 | ): ISwaggerOperation { 459 | const operation: ISwaggerOperation = { 460 | operationId: propertyKey, 461 | tags: [], 462 | }; 463 | if (args.description) { 464 | operation.description = args.description; 465 | } 466 | if (args.summary) { 467 | operation.summary = args.summary; 468 | } 469 | if (args.produces && args.produces.length > 0) { 470 | operation.produces = args.produces; 471 | } 472 | 473 | if (args.consumes && args.consumes.length > 0) { 474 | operation.consumes = args.consumes; 475 | } 476 | 477 | if (args.tags && args.tags.length > 0) { 478 | operation.tags = args.tags; 479 | } 480 | 481 | if (args.deprecated) { 482 | operation.deprecated = args.deprecated; 483 | } 484 | 485 | if (args.parameters) { 486 | operation.parameters = []; 487 | if (args.parameters.header) { 488 | operation.parameters = _.concat( 489 | operation.parameters, 490 | this.buildParameters( 491 | SwaggerDefinitionConstant.Parameter.In.HEADER, 492 | args.parameters.header 493 | ) 494 | ); 495 | } 496 | if (args.parameters.path) { 497 | operation.parameters = _.concat( 498 | operation.parameters, 499 | this.buildParameters( 500 | SwaggerDefinitionConstant.Parameter.In.PATH, 501 | args.parameters.path 502 | ) 503 | ); 504 | } 505 | if (args.parameters.query) { 506 | operation.parameters = _.concat( 507 | operation.parameters, 508 | this.buildParameters( 509 | SwaggerDefinitionConstant.Parameter.In.QUERY, 510 | args.parameters.query 511 | ) 512 | ); 513 | } 514 | if (args.parameters.body) { 515 | operation.parameters = _.concat( 516 | operation.parameters, 517 | this.buildBodyOperationParameter(args.parameters.body) 518 | ); 519 | } 520 | if (args.parameters.formData) { 521 | operation.parameters = _.concat( 522 | operation.parameters, 523 | this.buildParameters( 524 | SwaggerDefinitionConstant.Parameter.In.FORM_DATA, 525 | args.parameters.formData 526 | ) 527 | ); 528 | } 529 | } 530 | 531 | if (args.responses) { 532 | operation.responses = this.buildOperationResponses(args.responses); 533 | } 534 | 535 | if (args.security) { 536 | operation.security = this.buildOperationSecurity(args.security); 537 | } 538 | 539 | return operation; 540 | } 541 | 542 | private buildOperationResponses(responses: { 543 | [key: string]: IApiOperationArgsBaseResponse; 544 | }): { 545 | [key: string]: ISwaggerOperationResponse; 546 | } { 547 | const swaggerOperationResponses: { 548 | [key: string]: ISwaggerOperationResponse; 549 | } = {}; 550 | for (const responseIndex in responses) { 551 | const response: IApiOperationArgsBaseResponse = 552 | responses[responseIndex]; 553 | const newSwaggerOperationResponse: ISwaggerOperationResponse = {}; 554 | if (response.description) { 555 | newSwaggerOperationResponse.description = response.description; 556 | } else { 557 | switch (responseIndex) { 558 | case '200': 559 | newSwaggerOperationResponse.description = 'Success'; 560 | break; 561 | case '201': 562 | newSwaggerOperationResponse.description = 'Created'; 563 | break; 564 | case '202': 565 | newSwaggerOperationResponse.description = 'Accepted'; 566 | break; 567 | case '203': 568 | newSwaggerOperationResponse.description = 569 | 'Non-Authoritative Information'; 570 | break; 571 | case '204': 572 | newSwaggerOperationResponse.description = 'No Content'; 573 | break; 574 | case '205': 575 | newSwaggerOperationResponse.description = 576 | 'Reset Content'; 577 | break; 578 | case '206': 579 | newSwaggerOperationResponse.description = 580 | 'Partial Content'; 581 | break; 582 | case '400': 583 | newSwaggerOperationResponse.description = 584 | 'Client error and Bad Request'; 585 | break; 586 | case '401': 587 | newSwaggerOperationResponse.description = 588 | 'Client error and Unauthorized'; 589 | break; 590 | case '404': 591 | newSwaggerOperationResponse.description = 592 | 'Client error and Not Found'; 593 | break; 594 | case '406': 595 | newSwaggerOperationResponse.description = 596 | 'Client error and Not Acceptable'; 597 | break; 598 | case '500': 599 | newSwaggerOperationResponse.description = 600 | 'Internal Server Error'; 601 | break; 602 | case '501': 603 | newSwaggerOperationResponse.description = 604 | 'Not Implemented'; 605 | break; 606 | case '503': 607 | newSwaggerOperationResponse.description = 608 | 'Service Unavailable'; 609 | break; 610 | default: 611 | newSwaggerOperationResponse.description = null; 612 | } 613 | } 614 | if (response.model) { 615 | const ref = this.buildRef(response.model); 616 | let newSwaggerOperationResponseSchema: ISwaggerOperationSchema = { 617 | $ref: ref, 618 | }; 619 | if ( 620 | _.isEqual( 621 | response.type, 622 | SwaggerDefinitionConstant.Response.Type.ARRAY 623 | ) 624 | ) { 625 | newSwaggerOperationResponseSchema = { 626 | items: { 627 | $ref: ref, 628 | } as ISwaggerOperationSchemaItems, 629 | type: SwaggerDefinitionConstant.Response.Type.ARRAY, 630 | }; 631 | } 632 | newSwaggerOperationResponse.schema = newSwaggerOperationResponseSchema; 633 | } 634 | swaggerOperationResponses[ 635 | responseIndex 636 | ] = newSwaggerOperationResponse; 637 | } 638 | return swaggerOperationResponses; 639 | } 640 | 641 | private buildBodyOperationParameter( 642 | bodyOperationArgsBaseParameter: IApiBodyOperationArgsBaseParameter 643 | ): ISwaggerOperationParameter[] { 644 | const swaggerOperationParameterList: ISwaggerOperationParameter[] = []; 645 | const swaggerOperationParameter = {} as ISwaggerOperationParameter; 646 | swaggerOperationParameter.name = bodyOperationArgsBaseParameter.name 647 | ? bodyOperationArgsBaseParameter.name 648 | : 'body'; 649 | swaggerOperationParameter.in = 'body'; 650 | swaggerOperationParameter.type = bodyOperationArgsBaseParameter.type; 651 | swaggerOperationParameter.description = 652 | bodyOperationArgsBaseParameter.description; 653 | swaggerOperationParameter.required = 654 | bodyOperationArgsBaseParameter.required; 655 | swaggerOperationParameter.format = 656 | bodyOperationArgsBaseParameter.format; 657 | swaggerOperationParameter.deprecated = 658 | bodyOperationArgsBaseParameter.deprecated; 659 | swaggerOperationParameter.allowEmptyValue = 660 | bodyOperationArgsBaseParameter.allowEmptyValue; 661 | swaggerOperationParameter.minimum = 662 | bodyOperationArgsBaseParameter.minimum; 663 | swaggerOperationParameter.maximum = 664 | bodyOperationArgsBaseParameter.maximum; 665 | swaggerOperationParameter.default = 666 | bodyOperationArgsBaseParameter.default; 667 | let schema = {} as ISwaggerOperationSchema; 668 | if (bodyOperationArgsBaseParameter.properties) { 669 | schema.type = 'object'; 670 | schema.required = []; 671 | schema.properties = {} as { 672 | [key: string]: ISwaggerPropertySchemaOperation; 673 | }; 674 | for (const propetyIndex in bodyOperationArgsBaseParameter.properties) { 675 | const propertyBodyOperationArgsBaseParameter = 676 | bodyOperationArgsBaseParameter.properties[propetyIndex]; 677 | const propertySchemaOperation = {} as ISwaggerPropertySchemaOperation; 678 | propertySchemaOperation.type = 679 | propertyBodyOperationArgsBaseParameter.type; 680 | schema.properties[propetyIndex] = propertySchemaOperation; 681 | if (propertyBodyOperationArgsBaseParameter.required) { 682 | schema.required.push(propetyIndex); 683 | } 684 | } 685 | } 686 | if (bodyOperationArgsBaseParameter.model) { 687 | const swaggerOperationSchema: ISwaggerOperationSchema = { 688 | $ref: this.buildRef(bodyOperationArgsBaseParameter.model), 689 | }; 690 | 691 | if (bodyOperationArgsBaseParameter.type !== 'array') { 692 | schema = swaggerOperationSchema; 693 | } else { 694 | schema.type = bodyOperationArgsBaseParameter.type; 695 | schema.items = { 696 | $ref: this.buildRef(bodyOperationArgsBaseParameter.model), 697 | }; 698 | } 699 | } 700 | swaggerOperationParameter.schema = schema; 701 | swaggerOperationParameterList.push(swaggerOperationParameter); 702 | return swaggerOperationParameterList; 703 | } 704 | 705 | private buildOperationSecurity(argsSecurity: { 706 | [key: string]: any[]; 707 | }): { [key: string]: any[] }[] { 708 | const securityToReturn = []; 709 | for (const securityIndex in argsSecurity) { 710 | const security: any[] = argsSecurity[securityIndex]; 711 | const result: { [key: string]: any[] } = {}; 712 | result[securityIndex] = security; 713 | securityToReturn.push(result); 714 | } 715 | return securityToReturn; 716 | } 717 | 718 | private buildParameters( 719 | type: string, 720 | parameters: { [key: string]: IApiOperationArgsBaseParameter } 721 | ): ISwaggerOperationParameter[] { 722 | const swaggerOperationParameter: ISwaggerOperationParameter[] = []; 723 | for (const parameterIndex in parameters) { 724 | const parameter: IApiOperationArgsBaseParameter = 725 | parameters[parameterIndex]; 726 | const newSwaggerOperationParameter: ISwaggerOperationParameter = { 727 | name: parameterIndex, 728 | in: type, 729 | type: parameter.type, 730 | items: parameter.items 731 | }; 732 | if (parameter.name) { 733 | newSwaggerOperationParameter.name = parameter.name; 734 | } 735 | newSwaggerOperationParameter.description = parameter.description; 736 | newSwaggerOperationParameter.required = parameter.required; 737 | newSwaggerOperationParameter.format = parameter.format; 738 | newSwaggerOperationParameter.deprecated = parameter.deprecated; 739 | newSwaggerOperationParameter.allowEmptyValue = 740 | parameter.allowEmptyValue; 741 | newSwaggerOperationParameter.minimum = parameter.minimum; 742 | newSwaggerOperationParameter.maximum = parameter.maximum; 743 | newSwaggerOperationParameter.default = parameter.default; 744 | swaggerOperationParameter.push(newSwaggerOperationParameter); 745 | } 746 | return swaggerOperationParameter; 747 | } 748 | 749 | private buildSwaggerOperation( 750 | operation: ISwaggerOperation, 751 | controller: IController 752 | ): ISwaggerOperation { 753 | if (_.isUndefined(operation.produces)) { 754 | operation.produces = this.data.produces; 755 | } 756 | if (_.isUndefined(operation.consumes)) { 757 | operation.consumes = this.data.consumes; 758 | } 759 | if (_.isUndefined(operation.security) && controller.security) { 760 | operation.security = this.buildOperationSecurity( 761 | controller.security 762 | ); 763 | } 764 | if (_.isUndefined(operation.deprecated) && controller.deprecated) { 765 | operation.deprecated = controller.deprecated; 766 | } 767 | if (this.globalResponses) { 768 | operation.responses = _.mergeWith( 769 | _.cloneDeep(this.globalResponses), 770 | operation.responses 771 | ); 772 | } 773 | if (operation.tags && operation.tags.length > 0) { 774 | operation.tags.unshift(_.upperFirst(controller.name)); 775 | } else { 776 | operation.tags = [_.upperFirst(controller.name)]; 777 | } 778 | return operation; 779 | } 780 | 781 | private buildRef(definition: string): string { 782 | return '#/definitions/'.concat(_.upperFirst(definition)); 783 | } 784 | } 785 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swagger-express-ts", 3 | "version": "1.1.1", 4 | "description": "Generate and serve swagger.json", 5 | "main": "index.js", 6 | "types": "index.d.ts", 7 | "typings": "index.d.ts", 8 | "scripts": { 9 | "build:lib": "echo \"Building lib...\" && gulp build:lib", 10 | "build": "echo \"Building...\" && gulp build", 11 | "clean": "echo \"Cleaning...\" && gulp clean", 12 | "test": "echo \"Testing...\" && npm run build && nyc mocha", 13 | "dev": "echo \"Developing...\" && nodemon", 14 | "start": "echo \"Starting...\" && npm run build && ts-node --project tsconfig.json src/index.ts", 15 | "publish": "npm publish dist", 16 | "prepare": "npm run build:lib" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/olivierlsc/swagger-express-ts.git" 21 | }, 22 | "author": "Olivier LIN-SI-CHENG", 23 | "license": "MIT", 24 | "keywords": [ 25 | "inversify", 26 | "inversifyjs", 27 | "swagger", 28 | "swagger2", 29 | "swagger-ui", 30 | "typescript", 31 | "expressjs", 32 | "express", 33 | "api rest", 34 | "documentation", 35 | "decorator", 36 | "generator", 37 | "swagger.json", 38 | "json", 39 | "rest" 40 | ], 41 | "bugs": { 42 | "url": "https://github.com/olivierlsc/swagger-express-ts/issues" 43 | }, 44 | "homepage": "https://github.com/olivierlsc/swagger-express-ts#readme", 45 | "dependencies": { 46 | "@types/body-parser": "^1.19.0", 47 | "@types/compression": "1.7.0", 48 | "@types/express": "^4.17.12", 49 | "@types/helmet": "0.0.48", 50 | "@types/inversify": "^2.0.33", 51 | "@types/lodash": "^4.14.170", 52 | "body-parser": "^1.19.0", 53 | "compression": "^1.7.4", 54 | "express": "^4.17.1", 55 | "helmet": "^4.6.0", 56 | "inversify": "^4.13.0", 57 | "inversify-express-utils": "^4.2.2", 58 | "lodash": "^4.17.21", 59 | "reflect-metadata": "^0.1.13", 60 | "save": "^2.4.0" 61 | }, 62 | "devDependencies": { 63 | "@types/chai": "^4.2.18", 64 | "@types/mocha": "^8.2.2", 65 | "@types/sinon": "^9.0.11", 66 | "chai": "^4.3.4", 67 | "gulp": "^4.0.2", 68 | "gulp-clean": "^0.4.0", 69 | "gulp-sourcemaps": "^3.0.0", 70 | "gulp-tslint": "^8.1.4", 71 | "gulp-typescript": "^5.0.1", 72 | "mocha": "^8.4.0", 73 | "nodemon": "^2.0.7", 74 | "nyc": "^15.1.0", 75 | "prettier": "2.2.1", 76 | "pretty-quick": "^3.1.1", 77 | "rimraf": "^3.0.2", 78 | "sinon": "^10.0.0", 79 | "source-map-support": "^0.5.19", 80 | "swagger-ui-dist": "^3.50.0", 81 | "ts-node": "^9.1.1", 82 | "tslint": "^6.1.3", 83 | "tslint-config-prettier": "^1.18.0", 84 | "typescript": "^4.3.4" 85 | }, 86 | "nyc": { 87 | "include": [ 88 | "src/**/*.ts", 89 | "lib/swagger-express-ts-lib/src/**/*.ts" 90 | ], 91 | "exclude": [ 92 | "src/index.ts" 93 | ], 94 | "extension": [ 95 | ".ts" 96 | ], 97 | "require": [ 98 | "ts-node/register" 99 | ], 100 | "reporter": [ 101 | "html", 102 | "cobertura" 103 | ], 104 | "sourceMap": true, 105 | "instrument": true 106 | }, 107 | "nodemonConfig": { 108 | "restartable": "rs", 109 | "watch": [ 110 | "src/**/*.ts", 111 | "lib/**/*.ts" 112 | ], 113 | "ext": "ts", 114 | "ignore": [ 115 | "test/*", 116 | "wiki/*", 117 | "swagger/*", 118 | "node_modules/*", 119 | "dist/*" 120 | ], 121 | "delay": "2500", 122 | "exec": "gulp build && ts-node --project tsconfig.json src/index.ts" 123 | }, 124 | "husky": { 125 | "hooks": { 126 | "pre-commit": "pretty-quick --staged" 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/cars/car.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import * as chai from 'chai'; 2 | import { CarController } from './car.controller'; 3 | import { CarsService } from './cars.service'; 4 | const expect = chai.expect; 5 | import * as express from 'express'; 6 | import * as sinon from 'sinon'; 7 | import { CarModel } from './car.model'; 8 | 9 | describe('CarController', () => { 10 | let carController: CarController; 11 | let carService: CarsService; 12 | 13 | beforeEach(() => { 14 | carService = {} as CarsService; 15 | carController = new CarController(carService); 16 | }); 17 | 18 | describe('getCar', () => { 19 | it('expect car', () => { 20 | const request: express.Request = null; 21 | const response: express.Response = {} as express.Response; 22 | const next: express.NextFunction = null; 23 | const id: string = '1'; 24 | const car: CarModel = {} as CarModel; 25 | const carsServiceGetCarByIdStub = sinon.stub().returns(car); 26 | carService.getCarById = carsServiceGetCarByIdStub; 27 | const responseJsonSpy = sinon.spy(); 28 | response.json = responseJsonSpy; 29 | 30 | carController.getCar(id, request, response, next); 31 | 32 | expect(carsServiceGetCarByIdStub.called).is.true; 33 | expect(responseJsonSpy.calledWith(car)).is.true; 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/cars/car.controller.ts: -------------------------------------------------------------------------------- 1 | import { injectable, inject } from 'inversify'; 2 | import 'reflect-metadata'; 3 | import { 4 | interfaces, 5 | controller, 6 | httpGet, 7 | requestParam, 8 | } from 'inversify-express-utils'; 9 | import { 10 | ApiPath, 11 | SwaggerDefinitionConstant, 12 | ApiOperationGet, 13 | } from 'swagger-express-ts'; 14 | import * as express from 'express'; 15 | import { CarsService } from './cars.service'; 16 | 17 | @ApiPath({ 18 | name: 'Cars', 19 | path: '/cars/{id}', 20 | }) 21 | @controller('/cars/:id') 22 | @injectable() 23 | export class CarController implements interfaces.Controller { 24 | constructor( 25 | @inject(CarsService.name) private carsService: CarsService 26 | ) {} 27 | 28 | @ApiOperationGet({ 29 | description: 'Get car object', 30 | parameters: { 31 | header: { 32 | 'x-custom-header': { 33 | required: true, 34 | type: SwaggerDefinitionConstant.Parameter.Type.STRING, 35 | }, 36 | }, 37 | path: { 38 | id: { 39 | required: true, 40 | type: SwaggerDefinitionConstant.Parameter.Type.STRING, 41 | }, 42 | }, 43 | }, 44 | responses: { 45 | 200: { 46 | model: 'Car', 47 | }, 48 | 400: {}, 49 | }, 50 | }) 51 | @httpGet('/') 52 | public getCar( 53 | @requestParam('id') id: string, 54 | request: express.Request, 55 | response: express.Response, 56 | next: express.NextFunction 57 | ): void { 58 | response.json(this.carsService.getCarById(id)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/cars/car.model.ts: -------------------------------------------------------------------------------- 1 | import { ApiModel, ApiModelProperty } from 'swagger-express-ts'; 2 | import { ConstructorModel } from '../constructors/constructor.model'; 3 | import { WheelModel } from './wheel.model'; 4 | 5 | @ApiModel({ 6 | description: 'Car description', 7 | name: 'Car', 8 | }) 9 | export class CarModel { 10 | @ApiModelProperty({ 11 | description: 'Id of car', 12 | required: true, 13 | example: ['123456789', '12345'], 14 | }) 15 | public id: string; 16 | 17 | @ApiModelProperty({ 18 | description: '', 19 | required: true, 20 | }) 21 | public name: string; 22 | 23 | @ApiModelProperty({ 24 | description: 'Description of car', 25 | required: true, 26 | }) 27 | public description: string; 28 | 29 | @ApiModelProperty({ 30 | description: 'Constructor of car', 31 | model: 'Constructor', 32 | }) 33 | public author: ConstructorModel; 34 | 35 | @ApiModelProperty({ 36 | description: 'Wheel car has. This is to demonstarte a cicrular reference works.', 37 | required: true, 38 | model: 'Wheel' 39 | }) 40 | public wheel: WheelModel | undefined; 41 | } 42 | -------------------------------------------------------------------------------- /src/cars/carbulk.controller.ts: -------------------------------------------------------------------------------- 1 | import { injectable, inject } from 'inversify'; 2 | import 'reflect-metadata'; 3 | import { interfaces, controller, httpPost, httpGet } from 'inversify-express-utils'; 4 | import { ApiPath, ApiOperationPost, ApiOperationGet, SwaggerDefinitionConstant } from 'swagger-express-ts'; 5 | import * as express from 'express'; 6 | import { CarsService } from './cars.service'; 7 | 8 | @ApiPath({ 9 | name: 'Cars', 10 | path: '/cars-bulk', 11 | }) 12 | @controller('/cars-bulk') 13 | @injectable() 14 | export class CarBulkController implements interfaces.Controller { 15 | constructor(@inject(CarsService.name) private carsService: CarsService) {} 16 | 17 | @ApiOperationPost({ 18 | description: 'Post car objects', 19 | summary: 'Post new cars', 20 | parameters: { 21 | body: { 22 | description: 'New car', 23 | required: true, 24 | model: 'Car', 25 | type: 'array', 26 | }, 27 | }, 28 | responses: { 29 | 200: { 30 | model: 'Car', 31 | }, 32 | 400: { description: 'Parameters fail' }, 33 | }, 34 | }) 35 | @httpPost('/') 36 | public postBulkCar( 37 | request: express.Request, 38 | response: express.Response 39 | ): void { 40 | if (!request.body) { 41 | return response.status(400).end(); 42 | } 43 | 44 | response.json(request.body); 45 | } 46 | 47 | @ApiOperationGet({ 48 | description: 'Get cars objects list by ids', 49 | summary: 'Get cars list by ids', 50 | parameters: { 51 | query: { 52 | ids: { 53 | type: 'array', 54 | required: true, 55 | items: { 56 | type: 'string' 57 | } 58 | } 59 | }, 60 | }, 61 | responses: { 62 | 200: { 63 | type: SwaggerDefinitionConstant.Response.Type.ARRAY, 64 | model: 'Car', 65 | }, 66 | }, 67 | security: { 68 | apiKeyHeader: [], 69 | }, 70 | }) 71 | @httpGet('/') 72 | public getCarsByIds( 73 | request: express.Request, 74 | response: express.Response 75 | ): void { 76 | response.json(this.carsService.getCarsByIds(request.query.ids as string[])); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/cars/cars.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import * as chai from 'chai'; 2 | import { CarsController } from './cars.controller'; 3 | import { CarsService } from './cars.service'; 4 | const expect = chai.expect; 5 | import * as express from 'express'; 6 | import * as sinon from 'sinon'; 7 | import { CarModel } from './car.model'; 8 | 9 | describe('CarsController', () => { 10 | let carsController: CarsController; 11 | let carsService: CarsService; 12 | 13 | beforeEach(() => { 14 | carsService = {} as CarsService; 15 | carsController = new CarsController(carsService); 16 | }); 17 | describe('GET:/cars', () => { 18 | it('expect cars list', () => { 19 | let request: express.Request; 20 | const response: express.Response = {} as express.Response; 21 | let next: express.NextFunction; 22 | const carsList: CarModel[] = []; 23 | const carsServiceGetCarsStub = sinon 24 | .stub() 25 | .returns(carsList); 26 | carsService.getCars = carsServiceGetCarsStub; 27 | const responseJsonSpy = sinon.spy(); 28 | response.json = responseJsonSpy; 29 | 30 | carsController.getCars(request, response, next); 31 | 32 | expect(carsServiceGetCarsStub.called).is.true; 33 | expect(responseJsonSpy.calledWith(carsList)).is.true; 34 | }); 35 | }); 36 | 37 | describe('POST:/cars', () => { 38 | it('expect post car', () => { 39 | const request: express.Request = {} as express.Request; 40 | const response: express.Response = {} as express.Response; 41 | let next: express.NextFunction; 42 | const car: CarModel = {} as CarModel; 43 | const carsServiceAddCarStub = sinon.stub().returns(car); 44 | carsService.addCar = carsServiceAddCarStub; 45 | const responseJsonSpy = sinon.spy(); 46 | response.json = responseJsonSpy; 47 | request.body = {}; 48 | 49 | carsController.postCar(request, response, next); 50 | 51 | expect(carsServiceAddCarStub.calledWith(request.body)).is 52 | .true; 53 | expect(responseJsonSpy.calledWith(car)).is.true; 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /src/cars/cars.controller.ts: -------------------------------------------------------------------------------- 1 | import * as express from 'express'; 2 | import { injectable, inject } from 'inversify'; 3 | import 'reflect-metadata'; 4 | import { 5 | controller, 6 | httpGet, 7 | interfaces, 8 | httpPost, 9 | requestParam, 10 | httpPut, 11 | } from 'inversify-express-utils'; 12 | import { 13 | ApiPath, 14 | ApiOperationGet, 15 | ApiOperationPost, 16 | SwaggerDefinitionConstant, 17 | ApiOperationPut, 18 | } from 'swagger-express-ts'; 19 | import { CarsService } from './cars.service'; 20 | import { CarModel } from './car.model'; 21 | 22 | @ApiPath({ 23 | path: '/cars', 24 | name: 'Cars', 25 | security: { apiKeyHeader: [] }, 26 | }) 27 | @controller('/cars') 28 | @injectable() 29 | export class CarsController implements interfaces.Controller { 30 | constructor(@inject(CarsService.name) private carsService: CarsService) {} 31 | 32 | @ApiOperationGet({ 33 | description: 'Get cars objects list', 34 | summary: 'Get cars list', 35 | responses: { 36 | 200: { 37 | type: SwaggerDefinitionConstant.Response.Type.ARRAY, 38 | model: 'Car', 39 | }, 40 | }, 41 | security: { 42 | apiKeyHeader: [], 43 | }, 44 | }) 45 | @httpGet('/') 46 | public getCars( 47 | request: express.Request, 48 | response: express.Response, 49 | next: express.NextFunction 50 | ): void { 51 | response.json(this.carsService.getCars()); 52 | } 53 | 54 | @ApiOperationPost({ 55 | description: 'Post car object', 56 | summary: 'Post new car', 57 | parameters: { 58 | body: { 59 | description: 'New car', 60 | required: true, 61 | model: 'Car', 62 | }, 63 | }, 64 | responses: { 65 | 200: { 66 | model: 'Car', 67 | }, 68 | 400: { description: 'Parameters fail' }, 69 | }, 70 | }) 71 | @httpPost('/') 72 | public postCar( 73 | request: express.Request, 74 | response: express.Response, 75 | next: express.NextFunction 76 | ): void { 77 | if (!request.body) { 78 | return response.status(400).end(); 79 | } 80 | const newCar = new CarModel(); 81 | newCar.id = request.body.id; 82 | newCar.name = request.body.name; 83 | newCar.description = request.body.description; 84 | newCar.author = request.body.author; 85 | this.carsService.addCar(request.body); 86 | response.json(request.body); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/cars/cars.service.spec.ts: -------------------------------------------------------------------------------- 1 | import * as chai from 'chai'; 2 | import { CarsService } from './cars.service'; 3 | import { CarModel } from './car.model'; 4 | const expect = chai.expect; 5 | 6 | describe('CarsService', () => { 7 | let carsService: CarsService; 8 | 9 | beforeEach(() => { 10 | carsService = new CarsService(); 11 | }); 12 | 13 | describe('getCars', () => { 14 | it('expect cars list', () => { 15 | const cars = carsService.getCars(); 16 | 17 | expect(cars).exist; 18 | }); 19 | }); 20 | 21 | describe('addCar', () => { 22 | it('expect new car', () => { 23 | const newCar: CarModel = {} as CarModel; 24 | const lengthBeforeAddCar = carsService.getCars().length; 25 | 26 | const car = carsService.addCar(newCar); 27 | 28 | expect(car).exist; 29 | const lengthAfterAddCar = carsService.getCars().length; 30 | expect(lengthBeforeAddCar < lengthAfterAddCar).is.true; 31 | }); 32 | }); 33 | 34 | describe('getCarById', () => { 35 | it('expect car by id', () => { 36 | const car = carsService.getCarById('1'); 37 | 38 | expect(car).exist; 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/cars/cars.service.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from 'inversify'; 2 | import 'reflect-metadata'; 3 | import { CarModel } from './car.model'; 4 | import * as _ from 'lodash'; 5 | 6 | @injectable() 7 | export class CarsService { 8 | private carsList: CarModel[] = [ 9 | { 10 | id: '1', 11 | name: 'Car 1', 12 | description: 'Description Car 1', 13 | version: '1.0.0', 14 | author: { 15 | id: '1', 16 | name: ['John DOE'], 17 | }, 18 | } as unknown as CarModel, 19 | { 20 | id: '2', 21 | name: 'Car 2', 22 | description: 'Description Car 2', 23 | version: '2.0.0', 24 | author: { 25 | id: '1', 26 | name: ['John DOE'], 27 | }, 28 | } as unknown as CarModel, 29 | ]; 30 | 31 | public getCars(): CarModel[] { 32 | return this.carsList; 33 | } 34 | 35 | public getCarsByIds(ids: string[]): CarModel[] { 36 | return this.carsList.filter(car => ids.includes(car.id)); 37 | } 38 | 39 | public addCar(car: CarModel): CarModel { 40 | this.carsList.push(car); 41 | return car; 42 | } 43 | 44 | public getCarById(id: string): CarModel { 45 | return _.find(this.carsList, (car: CarModel) => { 46 | return _.isEqual(car.id, id); 47 | }); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/cars/wheel.model.ts: -------------------------------------------------------------------------------- 1 | import { ApiModel, ApiModelProperty } from 'swagger-express-ts'; 2 | import { CarModel } from './car.model'; 3 | 4 | @ApiModel({ 5 | description: 'Car description', 6 | name: 'Wheel', 7 | }) 8 | export class WheelModel { 9 | @ApiModelProperty({ 10 | description: 'Id of wheel.', 11 | required: true, 12 | example: ['123456789', '12345'], 13 | }) 14 | public id: string; 15 | 16 | @ApiModelProperty({ 17 | description: 'Car wheel belongs to. This is to demonstrate a circular reference works.', 18 | required: true, 19 | model: 'Car', 20 | itemType: 'CarModel' 21 | }) 22 | public car: CarModel | undefined; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/constructors/constructor.model.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApiModel, 3 | ApiModelProperty, 4 | SwaggerDefinitionConstant, 5 | } from 'swagger-express-ts'; 6 | 7 | @ApiModel({ 8 | description: 'Description Constructor.', 9 | name: 'Constructor', 10 | }) 11 | export class ConstructorModel { 12 | @ApiModelProperty({ 13 | description: 'Id of Constructor', 14 | required: true, 15 | }) 16 | public id: string; 17 | 18 | @ApiModelProperty({ 19 | description: 'Name of Constructor', 20 | required: true, 21 | itemType: SwaggerDefinitionConstant.Model.Property.Type.STRING, 22 | }) 23 | public name: string[]; 24 | } 25 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as bodyParser from 'body-parser'; 2 | import * as express from 'express'; 3 | import 'reflect-metadata'; 4 | import { Container } from 'inversify'; 5 | import { 6 | interfaces, 7 | InversifyExpressServer, 8 | TYPE, 9 | } from 'inversify-express-utils'; 10 | import { CarsController } from './cars/cars.controller'; 11 | import * as swagger from 'swagger-express-ts'; 12 | // tslint:disable-next-line: no-duplicate-imports 13 | import { SwaggerDefinitionConstant } from 'swagger-express-ts'; 14 | const config = require('../config.json'); 15 | import { CarController } from './cars/car.controller'; 16 | import { CarBulkController } from './cars/carbulk.controller'; 17 | import { CarsService } from './cars/cars.service'; 18 | 19 | import * as _ from 'lodash'; 20 | 21 | // import models 22 | import { CarModel } from './cars/car.model'; 23 | import { WheelModel } from './cars/wheel.model'; 24 | import './constructors/constructor.model'; 25 | 26 | // set up container 27 | const container = new Container(); 28 | 29 | // note that you *must* bind your controllers to Controller 30 | container 31 | .bind(TYPE.Controller) 32 | .to(CarsController) 33 | .inSingletonScope() 34 | .whenTargetNamed(CarsController.name); 35 | container 36 | .bind(TYPE.Controller) 37 | .to(CarBulkController) 38 | .inSingletonScope() 39 | .whenTargetNamed(CarBulkController.name); 40 | container 41 | .bind(TYPE.Controller) 42 | .to(CarController) 43 | .inSingletonScope() 44 | .whenTargetNamed(CarController.name); 45 | container 46 | .bind(CarsService.name) 47 | .to(CarsService) 48 | .inSingletonScope(); 49 | 50 | container.bind(CarModel.name).to(CarModel); 51 | container.bind(WheelModel.name).to(WheelModel); 52 | 53 | 54 | // create server 55 | const server = new InversifyExpressServer(container); 56 | 57 | server.setConfig((app: any) => { 58 | app.use('/api-docs/swagger', express.static('swagger')); 59 | app.use( 60 | '/api-docs/swagger/assets', 61 | express.static('node_modules/swagger-ui-dist') 62 | ); 63 | app.use(bodyParser.json()); 64 | app.use( 65 | swagger.express({ 66 | definition: { 67 | info: { 68 | title: 'My api', 69 | version: '1.0', 70 | }, 71 | models: { 72 | ApiError: { 73 | properties: { 74 | code: { 75 | type: 76 | SwaggerDefinitionConstant.Model.Property 77 | .Type.STRING, 78 | example: ['400'], 79 | }, 80 | message: { 81 | type: 82 | SwaggerDefinitionConstant.Model.Property 83 | .Type.STRING, 84 | example: ['Name of car is required.'], 85 | }, 86 | }, 87 | }, 88 | }, 89 | responses: { 90 | 500: {}, 91 | }, 92 | externalDocs: { 93 | url: 'My url', 94 | }, 95 | securityDefinitions: { 96 | apiKeyHeader: { 97 | type: SwaggerDefinitionConstant.Security.Type.API_KEY, 98 | in: SwaggerDefinitionConstant.Security.In.HEADER, 99 | name: 'apiHeader', 100 | }, 101 | }, 102 | }, 103 | }) 104 | ); 105 | }); 106 | 107 | server.setErrorConfig((app: any) => { 108 | app.use( 109 | ( 110 | err: Error, 111 | request: express.Request, 112 | response: express.Response, 113 | next: express.NextFunction 114 | ) => { 115 | console.error(err.stack); 116 | response.status(500).send('Something broke!'); 117 | } 118 | ); 119 | }); 120 | 121 | const app = server.build(); 122 | 123 | if (!_.isEqual(process.env.NODE_ENV, 'test')) { 124 | app.listen(config.port); 125 | console.info('Server is listening on port : ' + config.port); 126 | } 127 | -------------------------------------------------------------------------------- /swagger/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Swagger UI 7 | 9 | 10 | 11 | 12 | 30 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
70 | 71 | 72 | 73 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --compilers ts-node/register 2 | --require source-map-support/register 3 | --full-trace 4 | --bail 5 | src/**/*.spec.ts lib/swagger-express-ts-lib/src/**/*.spec.ts -------------------------------------------------------------------------------- /tsconfig.dev.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "outDir": "./node_modules/swagger-express-ts" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": 5 | "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */, 6 | "module": 7 | "commonjs" /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, 8 | "lib": [ 9 | "es2017", 10 | "dom" 11 | ] /* Specify library files to be included in the compilation: */, 12 | // "allowJs": true, /* Allow javascript files to be compiled. */ 13 | // "checkJs": true, /* Report errors in .js files. */ 14 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 15 | "declaration": false /* Generates corresponding '.d.ts' file. */, 16 | "sourceMap": true /* Generates corresponding '.map' file. */, 17 | //"outFile": "index.js", /* Concatenate and emit output to single file. */ 18 | "outDir": "./built" /* Redirect output structure to the directory. */, 19 | //"rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 20 | // "removeComments": true, /* Do not emit comments to output. */ 21 | // "noEmit": true, /* Do not emit outputs. */ 22 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 23 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 24 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 25 | 26 | /* Strict Type-Checking Options */ 27 | //"strict": true, /* Enable all strict type-checking options. */ 28 | "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, 29 | "strictNullChecks": false /* Enable strict null checks. */, 30 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 31 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 32 | 33 | /* Additional Checks */ 34 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 35 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 36 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 37 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 38 | 39 | /* Module Resolution Options */ 40 | "moduleResolution": 41 | "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, 42 | "baseUrl": 43 | "./" /* Base directory to resolve non-absolute module names. */, 44 | //"paths": { 45 | //} /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */, 46 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 47 | "typeRoots": [ 48 | "node_modules/@types", 49 | "node_modules/swagger-express-ts" 50 | ] /* List of folders to include type definitions from. */, 51 | //"types": [ 52 | // "express", 53 | // "inversify", 54 | // "reflect-metadata", 55 | // "compression", 56 | // "helmet", 57 | // "mocha", 58 | // "sinon", 59 | // "lodash", 60 | // "chai" 61 | //] /* Type declaration files to be included in compilation. */, 62 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 63 | 64 | /* Source Map Options */ 65 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 66 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 67 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 68 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 69 | 70 | /* Experimental Options */ 71 | "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, 72 | "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */ 73 | }, 74 | "exclude": ["node_modules"], 75 | "include": ["src/**/*.ts"] 76 | } 77 | -------------------------------------------------------------------------------- /tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "outDir": "./dist/swagger-express-ts", 6 | "baseUrl": "./", 7 | "typeRoots": ["node_modules/@types"], 8 | "paths": {} 9 | }, 10 | "exclude": ["node_modules", "lib/swagger-express-ts-lib/src/**/*.spec.ts"], 11 | "include": ["lib/swagger-express-ts-lib/src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:latest", "tslint-config-prettier"], 4 | "jsRules": {}, 5 | "rules": { 6 | "no-console": false, 7 | "ordered-imports": false, 8 | "no-unused-expression": false, 9 | "no-shadowed-variable": false, 10 | "no-var-requires": false, 11 | "member-ordering": false, 12 | "no-implicit-dependencies": false, 13 | "no-empty-interface": false, 14 | "object-literal-sort-keys": false, 15 | "no-object-literal-type-assertion": false, 16 | "forin": false 17 | }, 18 | "rulesDirectory": [] 19 | } 20 | -------------------------------------------------------------------------------- /wiki/README.md: -------------------------------------------------------------------------------- 1 | # Wiki 2 | 3 | Welcome to the SwaggerExpressTS wiki! 4 | 5 | ## Installation and environment support 6 | 7 | - [Installation](./installation.md) 8 | 9 | ## Features and API 10 | 11 | - [Installation](./installation.md) 12 | - [Configuration](./configuration.md) 13 | - [@ApiModel](./api-model.decorator.md) 14 | - [@ApiModelProperty](./api-model-property.decorator.md) 15 | - [@ApiPath](./api-path.decorator.md) 16 | - [@ApiOperationGet](./api-operation-get.decorator.md) 17 | - [@ApiOperationPost](./api-operation-post.decorator.md) 18 | - [@ApiOperationPut](./api-operation-put.decorator.md) 19 | - [@ApiOperationPatch](./api-operation-patch.decorator.md) 20 | - [@ApiOperationDelete](./api-operation-delete.decorator.md) 21 | 22 | ## Test 23 | 24 | - [example-swagger-express-ts](https://github.com/olivierlsc/example-swagger-express-ts) -------------------------------------------------------------------------------- /wiki/api-model-property.decorator.md: -------------------------------------------------------------------------------- 1 | # @ApiModelProperty(args?: IApiModelPropertyArgs) 2 | 3 | Decorate property in model class. 4 | 5 | Example: 6 | 7 | ```ts 8 | @ApiModel({ 9 | description: "Version description", 10 | name: "Version" 11 | }) 12 | export class VersionModel { 13 | 14 | @ApiModelProperty({ 15 | description: "number value", 16 | enum : ['1', '2'] 17 | }) 18 | number: number; 19 | ... 20 | } 21 | ``` 22 | 23 | # IApiModelPropertyArgs 24 | 25 | ## required: boolean 26 | 27 | Define if property is required. 28 | 29 | * Optional 30 | 31 | ## format: string 32 | 33 | Define format. 34 | 35 | * Optional 36 | 37 | ## type: string 38 | 39 | Define type of property. 40 | 41 | * Optional 42 | 43 | ## description: string 44 | 45 | Define description of property. 46 | 47 | * Optional 48 | 49 | ## enum: string[] 50 | 51 | Define enum of property. 52 | 53 | * Optional 54 | 55 | ## model: string 56 | 57 | Define model 58 | 59 | * Optional 60 | 61 | ## itemType: string 62 | 63 | Define item type. 64 | 65 | * Optional 66 | 67 | ## example: any[] 68 | 69 | Define example. 70 | 71 | * Optional 72 | -------------------------------------------------------------------------------- /wiki/api-model.decorator.md: -------------------------------------------------------------------------------- 1 | # @ApiModel(args?: IApiModelArgs) 2 | 3 | Decorate model class. 4 | 5 | Example: 6 | 7 | ```ts 8 | @ApiModel({ 9 | description: "Version description", 10 | name: "Version" 11 | }) 12 | export class VersionModel { 13 | ... 14 | } 15 | ``` 16 | 17 | # IApiModelArgs 18 | 19 | ## description: string 20 | 21 | Define description 22 | - Optional 23 | 24 | ## name: string 25 | 26 | Define name 27 | - Optional 28 | - Default is name of model class -------------------------------------------------------------------------------- /wiki/api-operation-delete.decorator.md: -------------------------------------------------------------------------------- 1 | # @ApiOperationDelete(args: IApiOperationDeleteArgs) 2 | Decorate method for deleting a resource in your controller. 3 | 4 | Example: 5 | 6 | ```ts 7 | @ApiPath( { 8 | path : "/versions", 9 | name : "Version" 10 | } ) 11 | @controller( "/versions" ) 12 | @injectable() 13 | export class VersionController implements interfaces.Controller { 14 | public static TARGET_NAME: string = "VersionController"; 15 | private data: [any] = [ 16 | { 17 | id : "1", 18 | name : "Version 1", 19 | description : "Description Version 1", 20 | version : "1.0.0" 21 | }, 22 | { 23 | id : "2", 24 | name : "Version 2", 25 | description : "Description Version 2", 26 | version : "2.0.0" 27 | } 28 | ]; 29 | 30 | @ApiOperationDelete( { 31 | path : "/{id}", 32 | parameters : { 33 | path : { 34 | id : { 35 | description : "Id of version", 36 | type : SwaggerDefinitionConstant.Parameter.Type.STRING, 37 | required : true 38 | } 39 | } 40 | }, 41 | responses : { 42 | 200 : { description: "Success" } 43 | } 44 | } ) 45 | @httpDelete( "/:id" ) 46 | public deleteVersion( @requestParam( "id" ) id: string, request: express.Request, response: express.Response, next: express.NextFunction ): void { 47 | this.data.forEach( ( version: any, index: number )=> { 48 | if ( version.id === id ) { 49 | this.data.splice(index, 1); 50 | return response.status(200).end(); 51 | } 52 | } ); 53 | response.status( 404 ).end(); 54 | } 55 | } 56 | 57 | ``` 58 | 59 | # IApiOperationDeleteArgs 60 | 61 | ## path: string 62 | Define particular path of operation. Default is path parameter in [@ApiPath](./api-path.decorator.md). 63 | - Optional 64 | 65 | ## description: string 66 | Define description of operation. 67 | - Optional 68 | 69 | ## summary: string 70 | Define summary of operation. 71 | - Optional 72 | 73 | ## parameters: [IApiOperationArgsBaseParameters](./i-api-operation-args-base-parameters.md) 74 | Define parameters in path, body, query and formData. 75 | - Required 76 | 77 | ## responses: {[key: string]: [IApiOperationArgsBaseResponse](./i-api-operation-args-base-response.md)} 78 | Define all responses. 79 | - Required 80 | 81 | ## produces: string[] 82 | Define type list that resource produce. 83 | - Optional 84 | - Default is global type list defined in ISwaggerBuildDefinition when execute [.express(options: ISwaggerExpressOptions)](./configuration.md) 85 | 86 | ## security: {[key: string]: any[]} 87 | Define security 88 | - Optional 89 | 90 | Example: 91 | 92 | ```ts 93 | ... 94 | @ApiOperationDelete( { 95 | path : "/{id}", 96 | parameters : { 97 | path : { 98 | id : { 99 | description : "Id of version", 100 | type : SwaggerDefinitionConstant.Parameter.Type.STRING, 101 | required : true 102 | } 103 | } 104 | }, 105 | responses : { 106 | 200 : { description: "Success" } 107 | }, 108 | security : { 109 | basicAuth : [] 110 | } 111 | } ) 112 | ... 113 | } 114 | 115 | ``` 116 | 117 | ### Configuration 118 | 119 | Example: 120 | 121 | ```ts 122 | app.use( swagger.express( 123 | { 124 | definition : { 125 | ... 126 | securityDefinitions : { 127 | basicAuth : { 128 | type : SwaggerDefinitionConstant.Security.Type.BASIC_AUTHENTICATION 129 | }, 130 | apiKeyHeader : { 131 | type: SwaggerDefinitionConstant.Security.Type.API_KEY, 132 | in: SwaggerDefinitionConstant.Security.In.HEADER, 133 | name: "apiHeader" 134 | } 135 | } 136 | } 137 | } 138 | ) ); 139 | ``` 140 | 141 | ## deprecated: boolean 142 | Define deprecated 143 | - Optional -------------------------------------------------------------------------------- /wiki/api-operation-get.decorator.md: -------------------------------------------------------------------------------- 1 | # @ApiOperationGet(args: IApiOperationGetArgs) 2 | Decorate method for getting a resource in your controller. 3 | 4 | Example: 5 | 6 | ```ts 7 | @ApiPath( { 8 | path : "/versions", 9 | name : "Version" 10 | } ) 11 | @controller( "/versions" ) 12 | @injectable() 13 | export class VersionController implements interfaces.Controller { 14 | public static TARGET_NAME: string = "VersionController"; 15 | private data: [any] = [ 16 | { 17 | id : "1", 18 | name : "Version 1", 19 | description : "Description Version 1", 20 | version : "1.0.0" 21 | }, 22 | { 23 | id : "2", 24 | name : "Version 2", 25 | description : "Description Version 2", 26 | version : "2.0.0" 27 | } 28 | ]; 29 | 30 | @ApiOperationGet( { 31 | description : "Get version object", 32 | summary : "Get version", 33 | responses : { 34 | 200 : { description : "Success", type : SwaggerDefinitionConstant.Response.Type.ARRAY , model : "Version" } 35 | } 36 | } ) 37 | @httpGet( "/" ) 38 | public getVersions( request: express.Request, response: express.Response, next: express.NextFunction ): void { 39 | response.json( this.data ); 40 | } 41 | } 42 | 43 | ``` 44 | 45 | # IApiOperationGetArgs 46 | 47 | ## path: string 48 | Define particular path of operation. Default is path parameter in [@ApiPath](./api-path.decorator.md). 49 | - Optional 50 | 51 | ## description: string 52 | Define description of operation. 53 | - Optional 54 | 55 | ## summary: string 56 | Define summary of operation. 57 | - Optional 58 | 59 | ## parameters: [IApiOperationArgsBaseParameters](./i-api-operation-args-base-parameters.md) 60 | Define parameters in path, body, query and formData. 61 | - Required 62 | 63 | ## responses: {[key: string]: [IApiOperationArgsBaseResponse](./i-api-operation-args-base-response.md)} 64 | Define all responses. 65 | - Required 66 | 67 | ## produces: string[] 68 | Define type list that resource produce. 69 | - Optional 70 | - Default is global type list defined in ISwaggerBuildDefinition when execute [.express(options: ISwaggerExpressOptions)](./configuration.md) 71 | 72 | ## security: {[key: string]: any[]} 73 | Define security 74 | - Optional 75 | 76 | Example: 77 | 78 | ```ts 79 | ... 80 | @ApiOperationGet( { 81 | ... 82 | security : { 83 | basicAuth : [] 84 | } 85 | } ) 86 | ... 87 | } 88 | 89 | ``` 90 | 91 | ### Configuration 92 | 93 | Example: 94 | 95 | ```ts 96 | app.use( swagger.express( 97 | { 98 | definition : { 99 | ... 100 | securityDefinitions : { 101 | basicAuth : { 102 | type : SwaggerDefinitionConstant.Security.Type.BASIC_AUTHENTICATION 103 | }, 104 | apiKeyHeader : { 105 | type: SwaggerDefinitionConstant.Security.Type.API_KEY, 106 | in: SwaggerDefinitionConstant.Security.In.HEADER, 107 | name: "apiHeader" 108 | } 109 | } 110 | } 111 | } 112 | ) ); 113 | ``` 114 | 115 | ## deprecated: boolean 116 | Define deprecated 117 | - Optional -------------------------------------------------------------------------------- /wiki/api-operation-patch.decorator.md: -------------------------------------------------------------------------------- 1 | # @ApiOperationPatch(args: IApiOperationPatchArgs) 2 | Decorate method for updating a field of resource in your controller. 3 | 4 | Example: 5 | 6 | ```ts 7 | @ApiPath( { 8 | path : "/versions", 9 | name : "Version" 10 | } ) 11 | @controller( "/versions" ) 12 | @injectable() 13 | export class VersionController implements interfaces.Controller { 14 | public static TARGET_NAME: string = "VersionController"; 15 | private data: [any] = [ 16 | { 17 | id : "1", 18 | name : "Version 1", 19 | description : "Description Version 1", 20 | version : "1.0.0" 21 | }, 22 | { 23 | id : "2", 24 | name : "Version 2", 25 | description : "Description Version 2", 26 | version : "2.0.0" 27 | } 28 | ]; 29 | 30 | @ApiOperationPatch( { 31 | path : "/{id}/description", 32 | description : "Patch description in version object", 33 | summary : "Patch description in version", 34 | parameters : { 35 | path: { 36 | id: { 37 | description : "Id of version", 38 | type : SwaggerDefinitionConstant.Parameter.Type.STRING, 39 | required : true 40 | } 41 | }, 42 | body : { description : "New version", required : true, model : "Version" } 43 | }, 44 | responses : { 45 | 200 : { description : "Success" }, 46 | 400 : { description : "Parameters fail" }, 47 | 404 : { description : "Version not found" } 48 | } 49 | } ) 50 | @httpPatch( "/:id/description" ) 51 | public patchVersionDescription( @requestParam( "id" ) id: string, request: express.Request, response: express.Response, next: express.NextFunction ): void { 52 | if ( ! request.body ) { 53 | return response.status( 400 ).end(); 54 | } 55 | this.data.forEach( ( version: any )=> { 56 | if ( version.id === id ) { 57 | version.description = request.body.description; 58 | return response.json( version ); 59 | } 60 | } ); 61 | response.status( 404 ).end(); 62 | } 63 | } 64 | 65 | ``` 66 | 67 | # IApiOperationPatchArgs 68 | 69 | ## path: string 70 | Define particular path of operation. Default is path parameter in [@ApiPath](./api-path.decorator.md). 71 | - Optional 72 | 73 | ## description: string 74 | Define description of operation. 75 | - Optional 76 | 77 | ## summary: string 78 | Define summary of operation. 79 | - Optional 80 | 81 | ## parameters: [IApiOperationArgsBaseParameters](./i-api-operation-args-base-parameters.md) 82 | Define parameters in path, body, query and formData. 83 | - Required 84 | 85 | ## responses: {[key: string]: [IApiOperationArgsBaseResponse](./i-api-operation-args-base-response.md)} 86 | Define all responses. 87 | - Required 88 | 89 | ## produces: string[] 90 | Define type list that resource produce. 91 | - Optional 92 | - Default is global type list defined in ISwaggerBuildDefinition when execute [.express(options: ISwaggerExpressOptions)](./configuration.md) 93 | 94 | ## security: {[key: string]: any[]} 95 | Define security 96 | - Optional 97 | 98 | Example: 99 | 100 | ```ts 101 | ... 102 | @ApiOperationPatch( { 103 | path : "/{id}/description", 104 | description : "Patch description in version object", 105 | summary : "Patch description in version", 106 | parameters : { 107 | path: { 108 | id: { 109 | description : "Id of version", 110 | type : SwaggerDefinitionConstant.Parameter.Type.STRING, 111 | required : true 112 | } 113 | }, 114 | body : { description : "New version", required : true, model : "Version" } 115 | }, 116 | responses : { 117 | 200 : { description : "Success" }, 118 | 400 : { description : "Parameters fail" }, 119 | 404 : { description : "Version not found" } 120 | }, 121 | security : { 122 | basicAuth : [] 123 | } 124 | } ) 125 | ... 126 | } 127 | 128 | ``` 129 | 130 | ### Configuration 131 | 132 | Example: 133 | 134 | ```ts 135 | app.use( swagger.express( 136 | { 137 | definition : { 138 | ... 139 | securityDefinitions : { 140 | basicAuth : { 141 | type : SwaggerDefinitionConstant.Security.Type.BASIC_AUTHENTICATION 142 | }, 143 | apiKeyHeader : { 144 | type: SwaggerDefinitionConstant.Security.Type.API_KEY, 145 | in: SwaggerDefinitionConstant.Security.In.HEADER, 146 | name: "apiHeader" 147 | } 148 | } 149 | } 150 | } 151 | ) ); 152 | ``` 153 | 154 | ## deprecated: boolean 155 | Define deprecated 156 | - Optional -------------------------------------------------------------------------------- /wiki/api-operation-post.decorator.md: -------------------------------------------------------------------------------- 1 | # @ApiOperationPost(args: IApiOperationPostArgs) 2 | Decorate method for create a resource in your controller. 3 | 4 | Example: 5 | 6 | ```ts 7 | @ApiPath( { 8 | path : "/versions", 9 | name : "Version" 10 | } ) 11 | @controller( "/versions" ) 12 | @injectable() 13 | export class VersionController implements interfaces.Controller { 14 | public static TARGET_NAME: string = "VersionController"; 15 | private data: [any] = [ 16 | { 17 | id : "1", 18 | name : "Version 1", 19 | description : "Description Version 1", 20 | version : "1.0.0" 21 | }, 22 | { 23 | id : "2", 24 | name : "Version 2", 25 | description : "Description Version 2", 26 | version : "2.0.0" 27 | } 28 | ]; 29 | 30 | @ApiOperationPost( { 31 | description : "Post version object", 32 | summary : "Post new version", 33 | parameters : { 34 | body : { description : "New version", required : true, model : "Version" } 35 | }, 36 | responses : { 37 | 200 : { description : "Success" }, 38 | 400 : { description : "Parameters fail" } 39 | } 40 | } ) 41 | @httpPost( "/" ) 42 | public postVersion( request: express.Request, response: express.Response, next: express.NextFunction ): void { 43 | if ( ! request.body ) { 44 | return response.status( 400 ).end(); 45 | } 46 | this.data.push( request.body ); 47 | response.json( request.body ); 48 | } 49 | } 50 | 51 | ``` 52 | 53 | # IApiOperationPostArgs 54 | 55 | ## path: string 56 | Define particular path of operation. Default is path parameter in [@ApiPath](./api-path.decorator.md). 57 | - Optional 58 | 59 | ## description: string 60 | Define description of operation. 61 | - Optional 62 | 63 | ## summary: string 64 | Define summary of operation. 65 | - Optional 66 | 67 | ## parameters: [IApiOperationArgsBaseParameters](./i-api-operation-args-base-parameters.md) 68 | Define parameters in path, body, query and formData. 69 | - Required 70 | 71 | ## responses: {[key: string]: [IApiOperationArgsBaseResponse](./i-api-operation-args-base-response.md)} 72 | Define all responses. 73 | - Required 74 | 75 | ## produces: string[] 76 | Define type list that resource produce. 77 | - Optional 78 | - Default is global type list defined in ISwaggerBuildDefinition when execute [.express(options: ISwaggerExpressOptions)](./configuration.md) 79 | 80 | ## security: {[key: string]: any[]} 81 | Define security 82 | - Optional 83 | 84 | Example: 85 | 86 | ```ts 87 | ... 88 | @ApiOperationPost( { 89 | description : "Post version object", 90 | summary : "Post new version", 91 | parameters : { 92 | body : { description : "New version", required : true, model : "Version" } 93 | }, 94 | responses : { 95 | 200 : { description : "Success" }, 96 | 400 : { description : "Parameters fail" } 97 | }, 98 | security : { 99 | basicAuth : [] 100 | } 101 | } ) 102 | ... 103 | } 104 | 105 | ``` 106 | 107 | ### Configuration 108 | 109 | Example: 110 | 111 | ```ts 112 | app.use( swagger.express( 113 | { 114 | definition : { 115 | ... 116 | securityDefinitions : { 117 | basicAuth : { 118 | type : SwaggerDefinitionConstant.Security.Type.BASIC_AUTHENTICATION 119 | }, 120 | apiKeyHeader : { 121 | type: SwaggerDefinitionConstant.Security.Type.API_KEY, 122 | in: SwaggerDefinitionConstant.Security.In.HEADER, 123 | name: "apiHeader" 124 | } 125 | } 126 | } 127 | } 128 | ) ); 129 | ``` 130 | 131 | ## deprecated: boolean 132 | Define deprecated 133 | - Optional -------------------------------------------------------------------------------- /wiki/api-operation-put.decorator.md: -------------------------------------------------------------------------------- 1 | # @ApiOperationPut(args: IApiOperationPutArgs) 2 | Decorate method for updating a resource in your controller. 3 | 4 | Example: 5 | 6 | ```ts 7 | @ApiPath( { 8 | path : "/versions", 9 | name : "Version" 10 | } ) 11 | @controller( "/versions" ) 12 | @injectable() 13 | export class VersionController implements interfaces.Controller { 14 | public static TARGET_NAME: string = "VersionController"; 15 | private data: [any] = [ 16 | { 17 | id : "1", 18 | name : "Version 1", 19 | description : "Description Version 1", 20 | version : "1.0.0" 21 | }, 22 | { 23 | id : "2", 24 | name : "Version 2", 25 | description : "Description Version 2", 26 | version : "2.0.0" 27 | } 28 | ]; 29 | 30 | @ApiOperationPut( { 31 | path : "/{id}", 32 | parameters : { 33 | path : { 34 | id : { 35 | description : "Id of version", 36 | type : SwaggerDefinitionConstant.Parameter.Type.STRING, 37 | required : true 38 | } 39 | }, 40 | body : { 41 | description : "Updated version", 42 | model : "Version", 43 | required : true 44 | } 45 | }, 46 | responses : { 47 | 200 : { model : "Version" } 48 | } 49 | } ) 50 | @httpPut( "/:id" ) 51 | public putVersion( @requestParam( "id" ) id: string, request: express.Request, response: express.Response, next: express.NextFunction ): void { 52 | if ( ! request.body ) { 53 | return response.status( 400 ).end(); 54 | } 55 | this.data.forEach( ( version: any, index: number )=> { 56 | if ( version.id === id ) { 57 | let newVersion = request.body; 58 | version.id = newVersion.id; 59 | version.name = newVersion.name; 60 | version.description = newVersion.description; 61 | version.version = newVersion.version; 62 | this.data[ index ] = version; 63 | return response.json( version ); 64 | } 65 | } ); 66 | response.status( 404 ).end(); 67 | } 68 | } 69 | 70 | ``` 71 | 72 | # IApiOperationPutArgs 73 | 74 | ## path: string 75 | Define particular path of operation. Default is path parameter in [@ApiPath](./api-path.decorator.md). 76 | - Optional 77 | 78 | ## description: string 79 | Define description of operation. 80 | - Optional 81 | 82 | ## summary: string 83 | Define summary of operation. 84 | - Optional 85 | 86 | ## parameters: [IApiOperationArgsBaseParameters](./i-api-operation-args-base-parameters.md) 87 | Define parameters in path, body, query and formData. 88 | - Required 89 | 90 | ## responses: {[key: string]: [IApiOperationArgsBaseResponse](./i-api-operation-args-base-response.md)} 91 | Define all responses. 92 | - Required 93 | 94 | ## produces: string[] 95 | Define type list that resource produce. 96 | - Optional 97 | - Default is global type list defined in ISwaggerBuildDefinition when execute [.express(options: ISwaggerExpressOptions)](./configuration.md) 98 | 99 | ## security: {[key: string]: any[]} 100 | Define security 101 | - Optional 102 | 103 | Example: 104 | 105 | ```ts 106 | ... 107 | @ApiOperationPut( { 108 | path : "/{id}", 109 | parameters : { 110 | path : { 111 | id : { 112 | description : "Id of version", 113 | type : SwaggerDefinitionConstant.Parameter.Type.STRING, 114 | required : true 115 | } 116 | }, 117 | body : { 118 | description : "Updated version", 119 | model : "Version", 120 | required : true 121 | } 122 | }, 123 | responses : { 124 | 200 : { model : "Version" } 125 | }, 126 | security : { 127 | basicAuth : [] 128 | } 129 | } ) 130 | ... 131 | } 132 | 133 | ``` 134 | 135 | ### Configuration 136 | 137 | Example: 138 | 139 | ```ts 140 | app.use( swagger.express( 141 | { 142 | definition : { 143 | ... 144 | securityDefinitions : { 145 | basicAuth : { 146 | type : SwaggerDefinitionConstant.Security.Type.BASIC_AUTHENTICATION 147 | }, 148 | apiKeyHeader : { 149 | type: SwaggerDefinitionConstant.Security.Type.API_KEY, 150 | in: SwaggerDefinitionConstant.Security.In.HEADER, 151 | name: "apiHeader" 152 | } 153 | } 154 | } 155 | } 156 | ) ); 157 | ``` 158 | 159 | ## deprecated: boolean 160 | Define deprecated 161 | - Optional -------------------------------------------------------------------------------- /wiki/api-path.decorator.md: -------------------------------------------------------------------------------- 1 | # @ApiPath(args: IApiPathArgs) 2 | 3 | Decorate your controller to declare a resource. 4 | 5 | Example: 6 | 7 | ```ts 8 | import { injectable } from "inversify"; 9 | import "reflect-metadata"; 10 | import { ApiPath } from "swagger-express-ts"; 11 | import { controller } from "inversify-express-utils"; 12 | 13 | @ApiPath( { 14 | path : "/version", 15 | name : "Version" 16 | } ) 17 | @controller( "/version" ) 18 | @injectable() 19 | export class VersionController implements interfaces.Controller { 20 | public static TARGET_NAME: string = "VersionController"; 21 | } 22 | ``` 23 | 24 | # IApiPathArgs 25 | 26 | ## path: string 27 | Define path of resource. 28 | - Required 29 | 30 | ## name: string 31 | Define name of resource. 32 | - Required 33 | 34 | ## description: string 35 | Define description of resource. 36 | - Optional 37 | 38 | ## security: {[key: string]: any[]} 39 | Define security to apply all operations from current path. 40 | - Optional 41 | 42 | Example: 43 | 44 | ```ts 45 | ... 46 | @ApiPath( { 47 | path : "/version", 48 | name : "Version", 49 | security : { 50 | basicAuth : [] 51 | } 52 | } ) 53 | ... 54 | ``` 55 | 56 | ### Configuration 57 | 58 | Example: 59 | 60 | ```ts 61 | app.use( swagger.express( 62 | { 63 | definition : { 64 | ... 65 | securityDefinitions : { 66 | basicAuth : { 67 | type : SwaggerDefinitionConstant.Security.Type.BASIC_AUTHENTICATION 68 | }, 69 | apiKeyHeader : { 70 | type: SwaggerDefinitionConstant.Security.Type.API_KEY, 71 | in: SwaggerDefinitionConstant.Security.In.HEADER, 72 | name: "apiHeader" 73 | } 74 | } 75 | } 76 | } 77 | ) ); 78 | ``` 79 | 80 | ## deprecated: boolean 81 | Define deprecated 82 | - Optional -------------------------------------------------------------------------------- /wiki/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | ## .express(options: ISwaggerExpressOptions) 4 | Example with default configuration: 5 | 6 | ```ts 7 | app.use( swagger.express({ 8 | definition : { 9 | info : { 10 | title : "My api" , 11 | version : "1.0" 12 | } , 13 | models : { 14 | Version : { 15 | properties : { 16 | id : { 17 | type : SwaggerDefinitionConstant.Model.Property.Type.STRING , 18 | required : true 19 | } , 20 | name : { 21 | type : SwaggerDefinitionConstant.Model.Property.Type.STRING , 22 | required : true 23 | } , 24 | description : { 25 | type : SwaggerDefinitionConstant.Model.Property.Type.STRING 26 | } , 27 | version : { 28 | type : SwaggerDefinitionConstant.Model.Property.Type.STRING 29 | } 30 | } 31 | } 32 | } , 33 | externalDocs : { 34 | url : "My url" 35 | } 36 | } 37 | }) ); 38 | ``` 39 | 40 | # ISwaggerExpressOptions 41 | 42 | ## path: string 43 | Define path to serve swagger.json 44 | - Optional. 45 | - Default is "/api-docs/swagger.json". 46 | 47 | ## definition: [ISwaggerBuildDefinition](./i-swagger-build-definition.md) 48 | Define swagger definition. 49 | - Required 50 | 51 | # Authentication 52 | 53 | ## Configuration 54 | 55 | Example: 56 | 57 | ```ts 58 | app.use( swagger.express( 59 | { 60 | definition : { 61 | ... 62 | securityDefinitions : { 63 | basicAuth : { 64 | type : SwaggerDefinitionConstant.Security.Type.BASIC_AUTHENTICATION 65 | }, 66 | apiKeyHeader : { 67 | type: SwaggerDefinitionConstant.Security.Type.API_KEY, 68 | in: SwaggerDefinitionConstant.Security.In.HEADER, 69 | name: "apiHeader" 70 | } 71 | } 72 | } 73 | } 74 | ) ); 75 | ``` 76 | 77 | ## Secure controller 78 | 79 | Example: 80 | 81 | ```ts 82 | ... 83 | @ApiPath( { 84 | path : "/version", 85 | name : "Version", 86 | security : { 87 | basicAuth : [] 88 | } 89 | } ) 90 | ... 91 | @ApiOperationGet( { 92 | ... 93 | security : { 94 | basicAuth : [] 95 | } 96 | } ) 97 | ... 98 | ``` 99 | -------------------------------------------------------------------------------- /wiki/i-api-body-operation-args-base-parameter.md: -------------------------------------------------------------------------------- 1 | # IApiBodyOperationArgsBaseParameter 2 | 3 | ## name: string 4 | 5 | Define name of parameter. 6 | 7 | * Optional 8 | 9 | ## description: string 10 | 11 | Define description of parameter. 12 | 13 | * Optional 14 | 15 | ## type: string 16 | 17 | Define type of parameter. 18 | 19 | * Optional 20 | 21 | ## required: boolean 22 | 23 | Define required of parameter. 24 | 25 | * Optional 26 | 27 | ## format: string 28 | 29 | Define format of parameter. 30 | 31 | * Optional 32 | 33 | ## minimum: number 34 | 35 | Define minimum of parameter. 36 | 37 | * Optional 38 | 39 | ## maximum: number 40 | 41 | Define maximum of parameter. 42 | 43 | * Optional 44 | 45 | ## default: number 46 | 47 | Define default of parameter. 48 | 49 | * Optional 50 | 51 | ## deprecated: boolean 52 | 53 | Define deprecated of parameter. 54 | 55 | * Optional 56 | 57 | ## allowEmptyValue: boolean 58 | 59 | Define allowEmptyValue of parameter. 60 | 61 | * Optional 62 | 63 | ## properties: { [key: string]: [IApiPropertyBodyOperationArgsBaseParameter](./i-api-property-body-operation-args-base-parameter.md) } 64 | 65 | Define properties of parameter. 66 | 67 | * Optional 68 | 69 | ## model: string 70 | 71 | Define model reference 72 | 73 | * Optional 74 | * If you want specify Array of model, you must set type with [SwaggerDefinitionConstant](./swagger-definition-constant.md).Definition.Property.Type.ARRAY 75 | -------------------------------------------------------------------------------- /wiki/i-api-operation-args-base-parameter.md: -------------------------------------------------------------------------------- 1 | # IApiOperationArgsBaseParameter 2 | 3 | ## name: string 4 | 5 | Define name of parameter. 6 | 7 | * Optional 8 | 9 | ## description: string 10 | 11 | Define description of parameter. 12 | 13 | * Optional 14 | 15 | ## type: string 16 | 17 | Define type of parameter. 18 | 19 | * Optional 20 | 21 | ## format: string 22 | 23 | Define format of parameter. 24 | 25 | * Optional 26 | 27 | ## deprecated: boolean 28 | 29 | Define if parameter is deprecated. 30 | 31 | * Optional 32 | 33 | ## allowEmptyValue: boolean 34 | 35 | Define if parameter is allow empty value. 36 | 37 | * Optional 38 | -------------------------------------------------------------------------------- /wiki/i-api-operation-args-base-parameters.md: -------------------------------------------------------------------------------- 1 | # IApiOperationArgsBaseParameters 2 | 3 | ## path: {[key: string]: [IApiOperationArgsBaseParameter](./i-api-operation-args-base-parameter.md)} 4 | Define path parameters. 5 | - Optional 6 | 7 | ## query: {[key: string]: [IApiOperationArgsBaseParameter](./i-api-operation-args-base-parameter.md)} 8 | Define query parameters. 9 | - Optional 10 | 11 | ## body: [IApiBodyOperationArgsBaseParameter](./i-api-body-operation-args-base-parameter.md) 12 | Define body parameters. 13 | - Optional 14 | 15 | ## formData: {[key: string]: [IApiOperationArgsBaseParameter](./i-api-operation-args-base-parameter.md)} 16 | Define formData parameters. 17 | - Optional 18 | -------------------------------------------------------------------------------- /wiki/i-api-operation-args-base-response.md: -------------------------------------------------------------------------------- 1 | # IApiOperationArgsBaseResponse 2 | 3 | ## description: string 4 | 5 | Define description of response. 6 | 7 | * Optional 8 | 9 | ## type: string 10 | 11 | Define type of response. 12 | 13 | * Optional 14 | 15 | ## model: string 16 | 17 | Define model reference 18 | 19 | * Optional 20 | * If you want specify Array of model, you must set type with [SwaggerDefinitionConstant](./swagger-definition-constant.md).Definition.Property.Type.ARRAY 21 | -------------------------------------------------------------------------------- /wiki/i-api-property-body-operation-args-base-parameter.md: -------------------------------------------------------------------------------- 1 | # IApiPropertyBodyOperationArgsBaseParameter 2 | 3 | ## type: string 4 | 5 | Define type of parameter. 6 | 7 | 8 | ## required: string 9 | 10 | Define required of parameter. 11 | 12 | * Optional -------------------------------------------------------------------------------- /wiki/i-swagger-build-definition-model-property.md: -------------------------------------------------------------------------------- 1 | # ISwaggerBuildDefinitionModelProperty 2 | 3 | ## type: string 4 | 5 | Define type of property. 6 | 7 | * Required 8 | * Example : [SwaggerDefinitionConstant](./swagger-definition-constant.md).Definition.Property.Type.STRING or "string" 9 | 10 | ## format: string 11 | 12 | Define format of property. 13 | 14 | * Optional 15 | * Example : [SwaggerDefinitionConstant](./swagger-definition-constant.md).Definition.Property.Format.INT_64 16 | 17 | ## required: boolean 18 | 19 | Define if property is required. 20 | 21 | * Optional 22 | * Default is false. 23 | 24 | ## model: string 25 | 26 | Define model reference 27 | 28 | * Optional 29 | * If you want specify Array of model, you must set type with [SwaggerDefinitionConstant](./swagger-definition-constant.md).Definition.Property.Type.ARRAY 30 | 31 | ## description: string 32 | 33 | Define description of property. 34 | 35 | * Optional 36 | 37 | ## enum: string[] 38 | 39 | Define enum of property. 40 | 41 | * Optional 42 | 43 | ## itemType: string 44 | 45 | Define item type. 46 | 47 | * Optional 48 | 49 | Example: 50 | 51 | ```ts 52 | ... 53 | app.use( 54 | swagger.express({ 55 | definition: { 56 | ... 57 | models: { 58 | Author: { 59 | name: { 60 | description: "Name of author", 61 | type: SwaggerDefinitionConstant.Model.Property.Type.ARRAY, 62 | itemType: 63 | SwaggerDefinitionConstant.Model.Property.ItemType.STRING, 64 | required: true 65 | } 66 | } 67 | } 68 | } 69 | ... 70 | } 71 | }) 72 | ); 73 | ... 74 | ``` 75 | 76 | ## example: any[] 77 | 78 | Define example. 79 | 80 | * Optional 81 | -------------------------------------------------------------------------------- /wiki/i-swagger-build-definition-model.md: -------------------------------------------------------------------------------- 1 | # ISwaggerBuildDefinitionModel 2 | 3 | ## description: string; 4 | 5 | Define description 6 | - Optional 7 | 8 | ## properties: {[key: string]: [ISwaggerBuildDefinitionModelProperty](./i-swagger-build-definition-model-property.md)} 9 | 10 | Define properties of model. 11 | - Required -------------------------------------------------------------------------------- /wiki/i-swagger-build-definition.md: -------------------------------------------------------------------------------- 1 | # ISwaggerBuildDefinition 2 | 3 | ## setBasePath: string 4 | 5 | Define base URL for all API. 6 | 7 | * Optional. 8 | * Default is "/" 9 | 10 | ## setOpenapi: string 11 | 12 | Define version of OpenAPI. 13 | 14 | * Optional. 15 | 16 | ## setInfo : [SwaggerInfo](./i-swagger-setInfo.md) 17 | 18 | Define setInfo. 19 | 20 | ## setConsumes: string[] 21 | 22 | Define the MIME types supported by the API for setConsumes. The root-level definition can be overridden in individual operations. 23 | 24 | * Optional 25 | * Default is [SwaggerDefinition](./swagger-definition-constant.md).Consume.JSON or "application/json". 26 | 27 | ## setProduces: string[] 28 | 29 | Define the MIME types supported by the API for setProduces. The root-level definition can be overridden in individual operations. 30 | 31 | * Optional 32 | * Default is [SwaggerDefinition](./swagger-definition-constant.md).Consume.JSON or "application/json". 33 | 34 | ## setSchemes: string[] 35 | 36 | Define Schemes. 37 | 38 | * Optional 39 | * Default is [SwaggerDefinition](./swagger-definition-constant.md).Scheme.HTTP = "http" 40 | 41 | ## setHost: string 42 | 43 | Define setHost. 44 | 45 | * Optional 46 | 47 | ## models: {[key: string]: [ISwaggerBuildDefinitionModel](./i-swagger-build-definition-model.md)} 48 | 49 | Define all model. 50 | 51 | * Required 52 | 53 | ## externalDocs: [ISwaggerExternalDocs](./i-swagger-external-docs.md) 54 | 55 | Define external docs 56 | 57 | * Optional 58 | 59 | ## securityDefinitions: {[key: string]: [ISwaggerSecurityDefinition](./i-swagger-security-definition.md)} 60 | 61 | Define security definitions 62 | 63 | * Optional 64 | 65 | ## responses: {[key: string]: [IApiOperationArgsBaseResponse](./i-api-operation-args-base-response.md)} 66 | 67 | Define global responses 68 | 69 | * Optional 70 | -------------------------------------------------------------------------------- /wiki/i-swagger-contact.md: -------------------------------------------------------------------------------- 1 | # ISwaggerContact 2 | 3 | ## name: string 4 | Define name of contact. 5 | - Optional 6 | 7 | ## url: string 8 | Define url of contact. 9 | - Optional 10 | 11 | ## email: string 12 | Define email of contact. 13 | - Optional -------------------------------------------------------------------------------- /wiki/i-swagger-external-docs.md: -------------------------------------------------------------------------------- 1 | # ISwaggerExternalDocs 2 | 3 | ## description: string 4 | Define description of external docs. 5 | - Optional 6 | 7 | ## url: string 8 | Define url of external docs/ 9 | - Required -------------------------------------------------------------------------------- /wiki/i-swagger-info.md: -------------------------------------------------------------------------------- 1 | # ISwaggerInfo 2 | 3 | ## title: string 4 | Define title of your API 5 | - Required 6 | 7 | ## description: string 8 | Define description of your API 9 | - Optional 10 | 11 | ## termsOfService: string 12 | - Optional 13 | 14 | ## contact: ISwaggerContact 15 | - Optional 16 | 17 | ## license: ISwaggerLicense 18 | - Optional 19 | 20 | ## version: string 21 | - Required -------------------------------------------------------------------------------- /wiki/i-swagger-license.md: -------------------------------------------------------------------------------- 1 | # ISwaggerLicense 2 | 3 | ## name: string 4 | Define name of license. 5 | - Required 6 | 7 | ## url: string 8 | Define URL of license. 9 | - Optional -------------------------------------------------------------------------------- /wiki/i-swagger-security-definition.md: -------------------------------------------------------------------------------- 1 | # ISwaggerSecurityDefinition 2 | 3 | ### type: string 4 | Define type of security 5 | - Required 6 | 7 | ### in: string 8 | Define where security set 9 | - Optional 10 | 11 | ### name: string 12 | Define name of security 13 | - Optional -------------------------------------------------------------------------------- /wiki/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olivierlsc/swagger-express-ts/8707dcb28a8db30f5f3f16dd95c2c339146ce6a5/wiki/img/logo.png -------------------------------------------------------------------------------- /wiki/img/swagger-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olivierlsc/swagger-express-ts/8707dcb28a8db30f5f3f16dd95c2c339146ce6a5/wiki/img/swagger-ui.png -------------------------------------------------------------------------------- /wiki/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | You can get the latest release and the type setDefinitions using npm: 4 | 5 | ```sh 6 | npm install swagger-express-ts reflect-metadata --save 7 | ``` 8 | 9 | swagger-express-ts requires the experimentalDecorators, emitDecoratorMetadata and lib compilation options in your tsconfig.json file. 10 | 11 | ```json 12 | { 13 | "compilerOptions": { 14 | "target": "es5", 15 | "lib": ["es6"], 16 | "types": ["reflect-metadata", "swagger-express-ts"], 17 | "module": "commonjs", 18 | "moduleResolution": "node", 19 | "experimentalDecorators": true, 20 | "emitDecoratorMetadata": true 21 | } 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /wiki/swagger-definition-constant.md: -------------------------------------------------------------------------------- 1 | # SwaggerDefinitionConstant 2 | 3 | ## Produce 4 | 5 | ### XML : string = "application/xml" 6 | 7 | ### JSON: string = "application/json" 8 | 9 | ## Scheme 10 | 11 | ### HTTP: string = "http" 12 | 13 | ### HTTPS: string = "https" 14 | 15 | ## Consume 16 | 17 | ### XML : string = "application/xml" 18 | 19 | ### JSON: string = "application/json" 20 | 21 | ## Model 22 | 23 | ### Type 24 | 25 | #### OBJECT: string = "object" 26 | 27 | ### Property 28 | 29 | #### Type 30 | 31 | ##### INTEGER: string = "integer" 32 | 33 | ##### STRING: string = "string" 34 | 35 | ##### ARRAY: string = "array" 36 | 37 | #### Format 38 | 39 | ##### INT_64: string = "int64" 40 | 41 | ## Parameter 42 | 43 | ### Type 44 | 45 | #### INTEGER: string = "integer" 46 | 47 | #### STRING: string = "string" 48 | 49 | #### ARRAY: string = "array" 50 | 51 | ### In 52 | 53 | #### PATH: string = "path" 54 | 55 | #### QUERY: string = "query" 56 | 57 | #### BODY: string = "body" 58 | 59 | #### FORM_DATA: string = "formData" 60 | 61 | ## Response 62 | 63 | ### Type 64 | 65 | #### INTEGER: string = "integer" 66 | 67 | #### STRING: string = "string" 68 | 69 | #### ARRAY: string = "array" --------------------------------------------------------------------------------