├── .autod.conf.js ├── .eslintignore ├── .eslintrc ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── workflows │ └── nodejs.yml ├── .gitignore ├── .prettierrc.json ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README.zh_CN.md ├── app.js ├── appveyor.yml ├── config └── config.default.js ├── example ├── egg-swagger-example │ ├── .autod.conf.js │ ├── .eslintignore │ ├── .eslintrc │ ├── .github │ │ └── workflows │ │ │ └── nodejs.yml │ ├── .gitignore │ ├── .travis.yml │ ├── README.md │ ├── app │ │ ├── controller │ │ │ └── home.js │ │ ├── public │ │ │ └── swagger.json │ │ ├── router.js │ │ └── schema │ │ │ ├── definitions │ │ │ ├── id.js │ │ │ ├── index.js │ │ │ └── no.js │ │ │ └── home.js │ ├── appveyor.yml │ ├── config │ │ ├── config.default.js │ │ └── plugin.js │ ├── jsconfig.json │ ├── package.json │ └── test │ │ └── app │ │ └── controller │ │ └── home.test.js ├── egg-swagger-ts-example │ ├── .autod.conf.js │ ├── .eslintignore │ ├── .eslintrc │ ├── .github │ │ └── workflows │ │ │ └── nodejs.yml │ ├── .gitignore │ ├── .travis.yml │ ├── README.md │ ├── app │ │ ├── controller │ │ │ └── home.ts │ │ ├── public │ │ │ └── swagger.json │ │ ├── router.ts │ │ ├── schema │ │ │ ├── definitions │ │ │ │ ├── id.ts │ │ │ │ ├── index.ts │ │ │ │ └── no.ts │ │ │ └── home.ts │ │ └── service │ │ │ └── Test.ts │ ├── appveyor.yml │ ├── config │ │ ├── config.default.ts │ │ ├── config.local.ts │ │ ├── config.prod.ts │ │ └── plugin.ts │ ├── package-lock.json │ ├── package.json │ ├── test │ │ └── app │ │ │ ├── controller │ │ │ └── home.test.ts │ │ │ └── service │ │ │ └── Test.test.ts │ ├── tsconfig.json │ └── typings │ │ ├── app │ │ ├── controller │ │ │ └── index.d.ts │ │ ├── index.d.ts │ │ └── service │ │ │ └── index.d.ts │ │ ├── config │ │ ├── index.d.ts │ │ └── plugin.d.ts │ │ └── index.d.ts ├── egg-swagger-ts-schema-example │ ├── .autod.conf.js │ ├── .eslintignore │ ├── .eslintrc │ ├── .github │ │ └── workflows │ │ │ └── nodejs.yml │ ├── .gitignore │ ├── .travis.yml │ ├── README.md │ ├── app │ │ ├── controller │ │ │ └── home.ts │ │ ├── public │ │ │ └── swagger.json │ │ ├── router.ts │ │ ├── schema │ │ │ ├── definitions │ │ │ │ └── Index.ts │ │ │ └── home.ts │ │ └── service │ │ │ └── Test.ts │ ├── appveyor.yml │ ├── config │ │ ├── config.default.ts │ │ ├── config.local.ts │ │ ├── config.prod.ts │ │ └── plugin.ts │ ├── package-lock.json │ ├── package.json │ ├── test │ │ └── app │ │ │ ├── controller │ │ │ └── home.test.ts │ │ │ └── service │ │ │ └── Test.test.ts │ ├── tsconfig.json │ └── typings │ │ ├── app │ │ ├── controller │ │ │ └── index.d.ts │ │ ├── index.d.ts │ │ └── service │ │ │ └── index.d.ts │ │ ├── config │ │ ├── index.d.ts │ │ └── plugin.d.ts │ │ └── index.d.ts └── swagger.json ├── lib ├── comment │ ├── comment_loader.js │ └── comment_parser.js ├── file_loader.js ├── router_loader.js ├── schema_loader.js ├── swagger.js ├── ts2schema_loader.js └── utils.js ├── package.json └── test ├── fixtures └── apps │ └── swagger-egg-router-test │ ├── app │ ├── controller │ │ ├── admin_test.js │ │ ├── home-test.js │ │ ├── posts.js │ │ └── v1 │ │ │ └── users.js │ ├── public │ │ └── swagger │ │ │ └── 0a6fc93a9412ea1ef3375cf695ffcbbd.json │ ├── router.js │ ├── router │ │ └── admin.js │ └── schema │ │ ├── admin_test.js │ │ ├── definitions │ │ ├── id.js │ │ └── index.js │ │ ├── home.js │ │ └── user.js │ ├── config │ └── config.default.js │ └── package.json ├── swagger-egg-static.test.js └── swagger-egg.test.js /.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | prefix: '^', 6 | plugin: 'autod-egg', 7 | test: [ 8 | 'test', 9 | 'benchmark', 10 | ], 11 | devdep: [ 12 | 'egg', 13 | 'egg-ci', 14 | 'egg-bin', 15 | 'autod', 16 | 'autod-egg', 17 | 'eslint', 18 | 'eslint-config-egg', 19 | ], 20 | exclude: [ 21 | './test/fixtures', 22 | './docs', 23 | './coverage', 24 | ], 25 | }; 26 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint-config-egg", 4 | "prettier" 5 | ], 6 | "rules": { 7 | "arrow-parens":"off" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | ##### Checklist 12 | 13 | 14 | - [ ] `npm test` passes 15 | - [ ] tests and/or benchmarks are included 16 | - [ ] documentation is changed or added 17 | - [ ] commit message follows commit guidelines 18 | 19 | ##### Affected core subsystem(s) 20 | 21 | 22 | 23 | ##### Description of change 24 | 25 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 60 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 8 | daysUntilClose: 7 9 | 10 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 11 | onlyLabels: [] 12 | 13 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 14 | exemptLabels: 15 | - pinned 16 | - security 17 | - "[Status] Maybe Later" 18 | 19 | # Set to true to ignore issues in a project (defaults to false) 20 | exemptProjects: false 21 | 22 | # Set to true to ignore issues in a milestone (defaults to false) 23 | exemptMilestones: false 24 | 25 | # Set to true to ignore issues with an assignee (defaults to false) 26 | exemptAssignees: false 27 | 28 | # Label to use when marking as stale 29 | staleLabel: wontfix 30 | 31 | # Comment to post when marking as stale. Set to `false` to disable 32 | markComment: > 33 | This issue has been automatically marked as stale because it has not had 34 | recent activity. It will be closed if no further activity occurs. Thank you 35 | for your contributions. 36 | 37 | # Comment to post when removing the stale label. 38 | # unmarkComment: > 39 | # Your comment here. 40 | 41 | # Comment to post when closing a stale Issue or Pull Request. 42 | # closeComment: > 43 | # Your comment here. 44 | 45 | # Limit the number of actions per hour, from 1-30. Default is 30 46 | limitPerRun: 30 47 | 48 | # Limit to only `issues` or `pulls` 49 | # only: issues 50 | 51 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': 52 | # pulls: 53 | # daysUntilStale: 30 54 | # markComment: > 55 | # This pull request has been automatically marked as stale because it has not had 56 | # recent activity. It will be closed if no further activity occurs. Thank you 57 | # for your contributions. 58 | 59 | # issues: 60 | # exemptLabels: 61 | # - confirmed 62 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Swagger Egg CI 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | schedule: 12 | - cron: '0 2 * * *' 13 | 14 | jobs: 15 | build: 16 | runs-on: ${{ matrix.os }} 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | node-version: [10.x, 12.x, 14.x, 15.x] 22 | os: [ubuntu-latest, windows-latest, macos-latest] 23 | 24 | steps: 25 | - name: Checkout Git Source 26 | uses: actions/checkout@v2 27 | 28 | - name: Use Node.js ${{ matrix.node-version }} 29 | uses: actions/setup-node@v2 30 | with: 31 | node-version: ${{ matrix.node-version }} 32 | check-latest: true 33 | # check and download the latest nodejs version(slower than using the cached version) 34 | 35 | - name: Cache Node.js modules 36 | uses: actions/cache@v2 37 | with: 38 | # npm cache files are stored in `~/.npm` on Linux/macOS 39 | path: ~/.npm 40 | key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} 41 | restore-keys: | 42 | ${{ runner.OS }}-node- 43 | ${{ runner.OS }}- 44 | 45 | - name: Install Dependencies 46 | run: npm ci 47 | # https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable 48 | 49 | - name: Continuous Integration 50 | run: npm run ci 51 | 52 | - name: Code Coverage 53 | uses: codecov/codecov-action@v1 54 | with: 55 | token: ${{ secrets.CODECOV_TOKEN }} 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | node_modules/ 4 | coverage/ 5 | .idea/ 6 | run/ 7 | .DS_Store 8 | *.swp 9 | .vscode/ 10 | package-lock.json 11 | .travis.yml 12 | .github/workflows/nodejs.yml 13 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "bracketSpacing": false, 4 | "endOfLine": "lf", 5 | "insertPragma": false, 6 | "printWidth": 120, 7 | "proseWrap": "preserve", 8 | "quoteProps": "as-needed", 9 | "requirePragma": false, 10 | "semi": true, 11 | "singleQuote": true, 12 | "tabWidth": 2, 13 | "trailingComma": "es5", 14 | "useTabs": false 15 | } 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: node_js 3 | node_js: 4 | - '10' 5 | - '12' 6 | - '14' 7 | before_install: 8 | - npm i npminstall -g 9 | install: 10 | - npminstall 11 | script: 12 | - npm run ci 13 | after_script: 14 | - npminstall codecov && codecov 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.7.5](https://github.com/JsonMa/swagger-egg/compare/v1.7.4...v1.7.5) (2022-03-31) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * :bug: convert file name to camelCase ([e339da2](https://github.com/JsonMa/swagger-egg/commit/e339da230d39a0fb32a8a48a55bf21c7d5ddad5a)) 7 | 8 | 9 | 10 | ## [1.7.3](https://github.com/JsonMa/swagger-egg/compare/v1.6.4...v1.7.3) (2022-03-28) 11 | 12 | 13 | ### Bug Fixes 14 | 15 | * :bug: add swagger object to app instance ([3493664](https://github.com/JsonMa/swagger-egg/commit/3493664e18279d7a90aa181d8c7c54b3c21cf4e0)) 16 | 17 | 18 | ### Features 19 | 20 | * :sparkles: add file md5 to disable cache ([0a635ec](https://github.com/JsonMa/swagger-egg/commit/0a635ec9b6a24006911530f0d90aabcbc20bb18c)) 21 | * :sparkles: add swagger ui config ([a318984](https://github.com/JsonMa/swagger-egg/commit/a318984e9c85b8d7b076396fabd05b1e6bd2f71f)) 22 | 23 | 24 | 25 | ## [1.7.2](https://github.com/JsonMa/swagger-egg/compare/v1.6.4...v1.7.2) (2022-03-25) 26 | 27 | 28 | ### Bug Fixes 29 | 30 | * :bug: add swagger object to app instance ([3493664](https://github.com/JsonMa/swagger-egg/commit/3493664e18279d7a90aa181d8c7c54b3c21cf4e0)) 31 | 32 | 33 | # [1.7.0](https://github.com/JsonMa/swagger-egg/compare/v1.6.4...v1.7.0) (2022-03-22) 34 | 35 | 36 | ### Features 37 | 38 | * :sparkles: add file md5 to disable cache ([0a635ec](https://github.com/JsonMa/swagger-egg/commit/0a635ec9b6a24006911530f0d90aabcbc20bb18c)) 39 | 40 | 41 | 42 | ## [1.6.4](https://github.com/JsonMa/swagger-egg/compare/v1.6.3...v1.6.4) (2022-03-22) 43 | 44 | 45 | ### Bug Fixes 46 | 47 | * :bug: fix same path coverd bug ([bb890ce](https://github.com/JsonMa/swagger-egg/commit/bb890ceb95119fa6654878ac6e89b05c0f78cbb0)) 48 | 49 | 50 | 51 | ## [1.6.3](https://github.com/JsonMa/swagger-egg/compare/v1.6.2...v1.6.3) (2022-03-18) 52 | 53 | 54 | ### Bug Fixes 55 | 56 | * :bug: fix path object not found bug ([7e83196](https://github.com/JsonMa/swagger-egg/commit/7e831963fc29b470508b393540ebc21b6f17d901)) 57 | 58 | 59 | 60 | ## [1.6.2](https://github.com/JsonMa/swagger-egg/compare/v1.6.1...v1.6.2) (2022-03-18) 61 | 62 | 63 | ### Bug Fixes 64 | 65 | * :bug: fix parameter in path undefined bug ([f0d4015](https://github.com/JsonMa/swagger-egg/commit/f0d4015086f0ca149c2e47d80b2e7eda2fd1cfee)) 66 | 67 | 68 | 69 | ## [1.6.1](https://github.com/JsonMa/swagger-egg/compare/v1.6.0...v1.6.1) (2022-03-18) 70 | 71 | 72 | ### Bug Fixes 73 | 74 | * :bug: fix path parameter bug ([9a746f0](https://github.com/JsonMa/swagger-egg/commit/9a746f086bbb8b905518fc3ac37b9366d2091a87)) 75 | 76 | 77 | 78 | # [1.6.0](https://github.com/JsonMa/swagger-egg/compare/v1.5.2...v1.6.0) (2022-03-17) 79 | 80 | 81 | ### Bug Fixes 82 | 83 | * :bug: fix controller not found bug in router file ([d6a4590](https://github.com/JsonMa/swagger-egg/commit/d6a45905a55b924e6336338660e8d333dbc31a57)) 84 | * eslint auto fix ([16f2a92](https://github.com/JsonMa/swagger-egg/commit/16f2a92ee00d3e24edd46edfb74a85b632f9a4cd)) 85 | 86 | 87 | ### Features 88 | 89 | * 支持 typescript 定义 schema ([608298e](https://github.com/JsonMa/swagger-egg/commit/608298e46f4a3b41a2ee8615331ad8f7497e7a51)) 90 | * Add default value in [@description](https://github.com/description) #parameters ([4846bec](https://github.com/JsonMa/swagger-egg/commit/4846becd803e07d35edcde83f3f98b6bb162ebeb)) 91 | * add egg-swagger-ts-schema-example ([1bc2ffc](https://github.com/JsonMa/swagger-egg/commit/1bc2ffcfa6168924b533918c04e46430b7ce31a9)) 92 | * Add typescriptJsonSchema option to readme ([feb10e7](https://github.com/JsonMa/swagger-egg/commit/feb10e7533d300101dd629dc53159a8b7808d279)) 93 | * update package-lock ([83db7b9](https://github.com/JsonMa/swagger-egg/commit/83db7b98e39d764aa4893ad9d0e7dde037f95e71)) 94 | 95 | 96 | 97 | ## [1.5.2](https://github.com/JsonMa/swagger-egg/compare/v1.4.1...v1.5.2) (2022-03-10) 98 | 99 | 100 | ### Bug Fixes 101 | 102 | * :bug: fix detect project language bug ([6ddf603](https://github.com/JsonMa/swagger-egg/commit/6ddf6038668c965fafe873f0124a9ee03dbbdf31)) 103 | * :bug: fix ts extend bug ([0d06265](https://github.com/JsonMa/swagger-egg/commit/0d06265dbbac305f08906b1b4daa443cb34900b0)) 104 | * fixed eslint ([3f56821](https://github.com/JsonMa/swagger-egg/commit/3f568218beacb79cc5e21c590f2ea8e2cea2ec95)) 105 | 106 | 107 | ### Features 108 | 109 | * :sparkles: add ts support ([e8ec535](https://github.com/JsonMa/swagger-egg/commit/e8ec535472de28b16c6f7ca7bba0cf2f723a557d)) 110 | * support ts ([1cf0998](https://github.com/JsonMa/swagger-egg/commit/1cf099816f8563a7c06ff9e99be4276ef600de74)) 111 | 112 | 113 | 114 | ## [1.5.1](https://github.com/JsonMa/swagger-egg/compare/v1.4.1...v1.5.1) (2022-03-10) 115 | 116 | 117 | ### Bug Fixes 118 | 119 | * :bug: fix ts extend bug ([0d06265](https://github.com/JsonMa/swagger-egg/commit/0d06265dbbac305f08906b1b4daa443cb34900b0)) 120 | * fixed eslint ([3f56821](https://github.com/JsonMa/swagger-egg/commit/3f568218beacb79cc5e21c590f2ea8e2cea2ec95)) 121 | 122 | 123 | ### Features 124 | 125 | * :sparkles: add ts support ([e8ec535](https://github.com/JsonMa/swagger-egg/commit/e8ec535472de28b16c6f7ca7bba0cf2f723a557d)) 126 | * support ts ([1cf0998](https://github.com/JsonMa/swagger-egg/commit/1cf099816f8563a7c06ff9e99be4276ef600de74)) 127 | 128 | 129 | 130 | 131 | ## [1.4.1](https://github.com/JsonMa/swagger-egg/compare/v1.4.0...v1.4.1) (2022-02-25) 132 | 133 | 134 | ### Bug Fixes 135 | 136 | * :bug: fix file name bug [#12](https://github.com/JsonMa/swagger-egg/issues/12) ([3d102f7](https://github.com/JsonMa/swagger-egg/commit/3d102f7df7e998543e41035c0a20a86cd4b25bd7)) 137 | 138 | 139 | 140 | # [1.4.0](https://github.com/JsonMa/swagger-egg/compare/v1.3.1...v1.4.0) (2022-01-27) 141 | 142 | 143 | ### Features 144 | 145 | * :sparkles: add support to simple parameters type ([d75a482](https://github.com/JsonMa/swagger-egg/commit/d75a4823140491c6145ec854bc5591ff9d4b2da3)) 146 | 147 | 148 | 149 | ## [1.3.1](https://github.com/JsonMa/swagger-egg/compare/v1.3.0...v1.3.1) (2022-01-24) 150 | 151 | 152 | ### Bug Fixes 153 | 154 | * fix windows crlf bug ([dbb0857](https://github.com/JsonMa/swagger-egg/commit/dbb0857ea9012dc2c695ac0f477ddc0a5e6a7ad8)) 155 | 156 | 157 | 158 | ## [1.2.2](https://github.com/JsonMa/swagger-egg/compare/v1.2.1...v1.2.2) (2021-10-26) 159 | 160 | 161 | ### Bug Fixes 162 | 163 | * **comment:** :bug: Fix windows crlf bug [#7](https://github.com/JsonMa/swagger-egg/issues/7) ([ef46724](https://github.com/JsonMa/swagger-egg/commit/ef467243747daa5d8a54ff1d3f746f670902a277)) 164 | 165 | 166 | 167 | ## [1.2.1](https://github.com/JsonMa/swagger-egg/compare/v1.1.0...v1.2.1) (2021-09-15) 168 | 169 | 170 | ### Bug Fixes 171 | 172 | * :bug: fix process blocking bug [#1](https://github.com/JsonMa/swagger-egg/issues/1) ([16b0492](https://github.com/JsonMa/swagger-egg/commit/16b0492a3424b1f924ea824bcfdbdb544944612e)) 173 | * :memo: remove useless tag ([cf4adff](https://github.com/JsonMa/swagger-egg/commit/cf4adff936bf0f1f483b1e71738ba3f5240237a2)) 174 | * :memo: update summary example doc ([4c38e6a](https://github.com/JsonMa/swagger-egg/commit/4c38e6abdb1b7009312bdf085a25cf63fe165ded)) 175 | * **example:** :bug: remove useless config and update dependency ([bc421cd](https://github.com/JsonMa/swagger-egg/commit/bc421cd380672a4a652fbf8ac87b5b16cc92a44e)) 176 | * **swaggerUI:** :bug: fix swagger prefix bug ([9e5490b](https://github.com/JsonMa/swagger-egg/commit/9e5490b931ca8db7d922aa7a6967ea7ac02e3707)) 177 | * **swaggerUI:** :bug: resolve egg static prefix bug ([72c229c](https://github.com/JsonMa/swagger-egg/commit/72c229c5536c8b07bf8f52e895b1ad2ca7536ba2)) 178 | * **swaggerUI:** :bug: resolve index.html error ([8a12980](https://github.com/JsonMa/swagger-egg/commit/8a1298083ccbf764938f6a25badcec968473da50)) 179 | * **swaggerUI:** :bug: resolve swagger index.html docExpansion bug ([d931ba2](https://github.com/JsonMa/swagger-egg/commit/d931ba2d8c0de6e4ee2b16d2dad268ea5e70a76f)) 180 | * **swaggerUI:** :bug: resolve swagger index.html error ([fe337c0](https://github.com/JsonMa/swagger-egg/commit/fe337c00f7dd18e05bb3a0beb5503ab21b6947d9)) 181 | 182 | 183 | ### Features 184 | 185 | * **example:** :sparkles: add $ref example ([96ad578](https://github.com/JsonMa/swagger-egg/commit/96ad57829a584d63f1a98e1b5a4f6865133d468f)) 186 | * :memo: add securityDefinitions doc ([7a46de1](https://github.com/JsonMa/swagger-egg/commit/7a46de1945c9067f039947fd7da80b55649256d5)) 187 | * :memo: socialify to project ([f5f2e74](https://github.com/JsonMa/swagger-egg/commit/f5f2e74b4eb5762f68602c3083e8be1a41aa1d79)) 188 | * :sparkles: add operationId to method object ([e34cb61](https://github.com/JsonMa/swagger-egg/commit/e34cb617d710e6bbf3faa796a28dd88b18ecc455)) 189 | * :sparkles: support JSDoc summary to swagger-egg ([27e1b6d](https://github.com/JsonMa/swagger-egg/commit/27e1b6df02c9149adaf32ba7f5219793c96fd17b)) 190 | * :sparkles: support path description ([08edea0](https://github.com/JsonMa/swagger-egg/commit/08edea0403cbedf68243b1b471ac75f4140487be)) 191 | 192 | 193 | 194 | # [1.2.0](https://github.com/JsonMa/swagger-egg/compare/v1.1.0...v1.2.0) (2021-08-23) 195 | 196 | ### Bug Fixes 197 | 198 | * **swaggerUI:** :bug: fix swagger prefix bug ([9e5490b](https://github.com/JsonMa/swagger-egg/commit/9e5490b931ca8db7d922aa7a6967ea7ac02e3707)) 199 | * **swaggerUI:** :bug: resolve egg static prefix bug ([72c229c](https://github.com/JsonMa/swagger-egg/commit/72c229c5536c8b07bf8f52e895b1ad2ca7536ba2)) 200 | * **swaggerUI:** :bug: resolve index.html error ([8a12980](https://github.com/JsonMa/swagger-egg/commit/8a1298083ccbf764938f6a25badcec968473da50)) 201 | * **swaggerUI:** :bug: resolve swagger index.html docExpansion bug ([d931ba2](https://github.com/JsonMa/swagger-egg/commit/d931ba2d8c0de6e4ee2b16d2dad268ea5e70a76f)) 202 | * **swaggerUI:** :bug: resolve swagger index.html error ([fe337c0](https://github.com/JsonMa/swagger-egg/commit/fe337c00f7dd18e05bb3a0beb5503ab21b6947d9)) 203 | 204 | 205 | ### Features 206 | 207 | * :memo: add securityDefinitions doc ([7a46de1](https://github.com/JsonMa/swagger-egg/commit/7a46de1945c9067f039947fd7da80b55649256d5)) 208 | * :memo: socialify to project ([f5f2e74](https://github.com/JsonMa/swagger-egg/commit/f5f2e74b4eb5762f68602c3083e8be1a41aa1d79)) 209 | * :sparkles: support JSDoc summary to swagger-egg ([27e1b6d](https://github.com/JsonMa/swagger-egg/commit/27e1b6df02c9149adaf32ba7f5219793c96fd17b)) 210 | * :sparkles: support path description ([08edea0](https://github.com/JsonMa/swagger-egg/commit/08edea0403cbedf68243b1b471ac75f4140487be)) 211 | 212 | 213 | 214 | ## 1.1.5 (2021-06-25) 215 | 216 | 217 | ### Bug Fixes 218 | 219 | * **comment:** :bug: resolve description parser bug ([dd433c4](https://github.com/JsonMa/swagger-egg/commit/dd433c4af17b185e2da459d61b60249229e168bc)) 220 | * **config:** :bug: remove useless field from default config ([ba77add](https://github.com/JsonMa/swagger-egg/commit/ba77added585a4f867a0643a075fbf04714a9857)) 221 | * **config:** remove swagger ui config ([61d8fe8](https://github.com/JsonMa/swagger-egg/commit/61d8fe8c832cd1ae62a73cedf4faebca1d72cf22)) 222 | * **swaggerUI:** :bug: fix swagger prefix bug ([9e5490b](https://github.com/JsonMa/swagger-egg/commit/9e5490b931ca8db7d922aa7a6967ea7ac02e3707)) 223 | * **swaggerUI:** :bug: resolve egg static prefix bug ([72c229c](https://github.com/JsonMa/swagger-egg/commit/72c229c5536c8b07bf8f52e895b1ad2ca7536ba2)) 224 | * **swaggerUI:** :bug: resolve index.html error ([8a12980](https://github.com/JsonMa/swagger-egg/commit/8a1298083ccbf764938f6a25badcec968473da50)) 225 | * **swaggerUI:** :bug: resolve swagger index.html docExpansion bug ([d931ba2](https://github.com/JsonMa/swagger-egg/commit/d931ba2d8c0de6e4ee2b16d2dad268ea5e70a76f)) 226 | * **swaggerUI:** :bug: resolve swagger index.html error ([fe337c0](https://github.com/JsonMa/swagger-egg/commit/fe337c00f7dd18e05bb3a0beb5503ab21b6947d9)) 227 | * **tag:** :bug: resolve tags comment not resolved bug ([d570628](https://github.com/JsonMa/swagger-egg/commit/d570628fb843c718687b970359580c625c5475f2)) 228 | * **utils:** remove unused methods ([1f1dc3a](https://github.com/JsonMa/swagger-egg/commit/1f1dc3a27a6a27340bf9ac07af3ab33c1c9313c6)) 229 | 230 | 231 | ### Features 232 | 233 | * **example:** :sparkles: add swagger 2.0 json file example ([cbd6083](https://github.com/JsonMa/swagger-egg/commit/cbd6083f481d2e43b5008cdf07b1c1006636b507)) 234 | * :sparkles: add file loader and swagger scanner ([d14731f](https://github.com/JsonMa/swagger-egg/commit/d14731f35da7fcce9fbbfd72490130cb323b8eb8)) 235 | * :sparkles: add swagger-ui to project ([4e2dacb](https://github.com/JsonMa/swagger-egg/commit/4e2dacb91059cd81956b429e0754cce1929d704d)) 236 | * :tada: first commit ([fba1b4f](https://github.com/JsonMa/swagger-egg/commit/fba1b4f73e69a7b03d8c00366080bed30915fe0c)) 237 | 238 | 239 | 240 | # 1.0.0 (2021-05-27) 241 | 242 | 243 | ### Features 244 | 245 | * :tada: first commit ([fba1b4f](https://github.com/eggjs/egg-swagger-egg/commit/fba1b4f73e69a7b03d8c00366080bed30915fe0c)) 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-present Alibaba Group Holding Limited and other contributors. 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 | # swagger-egg 2 | 3 | ![swagger-egg](https://socialify.git.ci/JsonMa/swagger-egg/image?description=1&font=Inter&forks=1&issues=1&language=1&owner=1&pattern=Floating%20Cogs&pulls=1&stargazers=1&theme=Light) 4 | 5 | [![NPM version][npm-image]][npm-url] 6 | [![build status][travis-image]][travis-url] 7 | [![Test coverage][codecov-image]][codecov-url] 8 | [![David deps][david-image]][david-url] 9 | [![Known Vulnerabilities][snyk-image]][snyk-url] 10 | [![npm download][download-image]][download-url] 11 | 12 | [中文文档](https://github.com/JsonMa/swagger-egg/blob/master/README.zh_CN.md) 13 | 14 | [npm-image]: https://img.shields.io/npm/v/swagger-egg.svg?style=flat-square 15 | [npm-url]: https://npmjs.org/package/swagger-egg 16 | [travis-image]: https://travis-ci.com/JsonMa/swagger-egg.svg?branch=master 17 | [travis-url]: https://travis-ci.org/jsonma/swagger-egg 18 | [codecov-image]: https://img.shields.io/codecov/c/github/jsonma/swagger-egg.svg?style=flat-square 19 | [codecov-url]: https://codecov.io/github/jsonma/swagger-egg?branch=master 20 | [david-image]: https://img.shields.io/david/jsonma/swagger-egg.svg?style=flat-square 21 | [david-url]: https://david-dm.org/jsonma/swagger-egg 22 | [snyk-image]: https://snyk.io/test/npm/swagger-egg/badge.svg?style=flat-square 23 | [snyk-url]: https://snyk.io/test/npm/swagger-egg 24 | [download-image]: https://img.shields.io/npm/dm/swagger-egg.svg?style=flat-square 25 | [download-url]: https://npmjs.org/package/swagger-egg 26 | 27 | 30 | An egg-swagger plugin (support Typescript) for serving a [Swagger UI](https://swagger.io/tools/swagger-ui/), params should follow [JSON Schema](http://json-schema.org/specification.html) specification (recommend use [Ajv](https://github.com/ajv-validator/ajv)),using [Swagger (OpenAPI v2)](https://swagger.io/specification/v2/) schemas automatically generated from your controller JSDoc comments. 31 | 32 | **CAUTION**: Require Node.js 10.x or higher! 33 | 34 | ## Install 35 | 36 | ```bash 37 | $ npm i swagger-egg --save 38 | ``` 39 | 40 | ## Usage 41 | Enable this plugin, visting `index.html` under `static resource directory` and you will get the Swagger UI page. Visiting `http://localhost:7001/public/index.html` to get the default `Swagger-UI` page. 42 | Project Example: 43 | - [JS Example](https://github.com/JsonMa/swagger-egg/tree/master/example/egg-swagger-example) 44 | - [TS Example](https://github.com/JsonMa/swagger-egg/tree/master/example/egg-swagger-ts-example) 45 | - [TS-Json-Schema Example ](https://github.com/JsonMa/swagger-egg/tree/master/example/egg-swagger-ts-schema-example) 46 | ```js 47 | // {app_root}/config/plugin.js 48 | exports.swaggerEgg = { 49 | enable: true, 50 | package: "swagger-egg", 51 | }; 52 | ``` 53 | 54 | ## Configuration 55 | + `swagger.info` is optional and will be generated from your application's `package.json` if not exist. 56 | + `swagger.tags` is required if controller's JSDoc comments used `tags`. 57 | 58 | ```js 59 | // {app_root}/config/config.default.js 60 | exports.swaggerEgg = { 61 | schema: { 62 | path: '/app/schema', // JSON Schema directory 63 | }, 64 | swagger: { 65 | info: { 66 | title: 'Test swagger', 67 | description: 'Testing the Fastify swagger API', 68 | version: '0.1.0' 69 | }, 70 | externalDocs: { 71 | url: 'https://swagger.io', 72 | description: 'Find more info here' 73 | }, 74 | host: '127.0.0.1:7001', // should be egg server's host, otherwise result in cross origin error 75 | schemes: ['http', 'https'], 76 | consumes: ['application/json'], 77 | produces: ['application/json'], 78 | tags: [ 79 | { name: 'user', description: 'User related end-points' } 80 | ], 81 | securityDefinitions: { 82 | api_key: { 83 | type: 'apiKey', // basic/apiKey/oauth2 84 | name: 'Authorization', // selfdefined parameter, usually use 'Authorization' 85 | in: 'header', // query or header, usually use 'header' 86 | }, 87 | github_auth: { 88 | type: 'oauth2', 89 | authorizationUrl: 'http://swagger.io/api/oauth/dialog', 90 | flow: 'implicit', 91 | scopes: { 92 | 'write:homes': 'modify home info', 93 | 'read:homes': 'read home info', 94 | }, 95 | }, 96 | }, 97 | security: [ 98 | { 99 | api_key: [], // select 'api_key' to security(defined in `securityDefinitions`) 100 | }, 101 | ], // Cacution: security is array type 102 | typescriptJsonSchema: false, // use typescript json schema. (see: https://github.com/YousefED/typescript-json-schema) 103 | } 104 | }; 105 | ``` 106 | 107 | see [config/config.default.js](config/config.default.js) for more detail. 108 | 109 | ## Grammer 110 | 111 | ### #swagger-api 112 | `#swagger-api` in front of JSDoc comments is **required**! 113 | 114 | ```js 115 | /** 116 | * #swagger-api 117 | * 118 | * @function index 119 | */ 120 | async index() { 121 | this.ctx.body = 'hi, #swagger-api example' 122 | } 123 | ``` 124 | 125 | ### @function {Name} 126 | The JSDoc `@function` is **required**, which is used to search router info from `app/router.js`. 127 | 128 | ```js 129 | /** 130 | * Function example #swagger-api 131 | * 132 | * @function index 133 | */ 134 | async index() { 135 | this.ctx.body = 'hi, function example' 136 | } 137 | ``` 138 | 139 | ### @summary {functionSummary} 140 | The JSDoc `@summary` is used to describe the function's summary. 141 | 142 | ```js 143 | /** 144 | * Function example #swagger-api 145 | * 146 | * @function index 147 | * @summary This is function's summary. 148 | */ 149 | async index() { 150 | this.ctx.body = 'hi, summary example' 151 | } 152 | ``` 153 | 154 | ### @description #tags {Tag1} {Tag2} ... 155 | `#tags` is used for logical grouping of operations by resources or any other qualifier. 156 | 157 | NOTE: Multiple tags should be separated by whitespace. 158 | 159 | ```js 160 | /** 161 | * Tags example #swagger-api 162 | * 163 | * @function index 164 | * @description #tags user admin 165 | */ 166 | async index() { 167 | this.ctx.body = 'hi, tags example' 168 | } 169 | ``` 170 | ### @description #produces {Mimetype1} {Mimetype2} ... 171 | `#produces` is used for declaring API response mimetype. 172 | 173 | NOTE: Multiple mimetypes should be separated by whitespace. 174 | 175 | ```js 176 | /** 177 | * Produces example #swagger-api 178 | * 179 | * @function index 180 | * @description #produces application/json 181 | */ 182 | async index() { 183 | this.ctx.body = 'hi, produces example' 184 | } 185 | ``` 186 | 187 | ### @description #consumes {Mimetype1} {Mimetype1} ... 188 | 189 | `#consumes` is used for declaring API request mimetype. 190 | 191 | NOTE: Multiple mimetypes should be separated by whitespace. 192 | 193 | ```js 194 | /** 195 | * Consumes example #swagger-api 196 | * 197 | * @function index 198 | * @description #consumes application/json 199 | */ 200 | async index() { 201 | this.ctx.body = 'hi, consumes example' 202 | } 203 | ``` 204 | 205 | ### @description #parameters {PrameterName} {In} {ParameterSchema|Type} {Required} - {Description} 206 | `#parameters` is used for declaring api request parameters. 207 | 208 | NOTE: Description is separated by ` - ` and others are separated by whitespace. 209 | 210 | NOTE: 211 | - `In` should be within `'query', 'header', 'path', 'formData', 'body'` according to Swagger specification. 212 | - `Required` should be `boolean type`. 213 | - `Type` should be within `'string', 'number', 'integer', 'boolean', 'array', 'file'`. 214 | ```js 215 | /** 216 | * Parameters example #swagger-api 217 | * 218 | * @function index 219 | * @description #parameters id path schema.id true - id parameter 220 | */ 221 | async index() { 222 | this.ctx.body = 'hi, parameters example' 223 | } 224 | ``` 225 | 226 | ### @description #responses {HttpStatus} {ResponseSchema} - {Description} 227 | 228 | `#responses` is used for declaring api response info. 229 | 230 | NOTE: Description is separated by ` - ` and others are separated by whitespace. 231 | 232 | ```js 233 | /** 234 | * Responses example #swagger-api 235 | * 236 | * @function index 237 | * @description #responses schema.user - user responses 238 | */ 239 | async index() { 240 | this.ctx.body = 'hi, responses example' 241 | } 242 | ``` 243 | 244 | ## Schema Example 245 | 246 | Schema should follow the [JSON Schema](http://json-schema.org/) specification. You can use [Ajv](https://ajv.js.org/guide/getting-started.html) to validate it. 247 | 248 | Change `swaggerEgg.schema.path` field in config file if you want to redefine it. 249 | 250 | ```js 251 | // {app_root}/app/schema/users.js 252 | 253 | module.exports = { 254 | type: 'object', 255 | properties: { 256 | id: { 257 | type: 'string', 258 | description: 'user id' 259 | }, 260 | name: { 261 | type: 'string', 262 | description: 'user name' 263 | }, 264 | age: { 265 | type: 'number', 266 | description: 'user age' 267 | }, 268 | }, 269 | required: [ 'id', 'name', 'age' ], 270 | additionalProperties: false, 271 | }; 272 | ``` 273 | 274 | ## Controller Example 275 | 276 | ```js 277 | // {app_root}/app/controller/users.js 278 | 279 | const Controller = require('egg').Controller; 280 | 281 | class UserController extends Controller { 282 | 283 | /** 284 | * Index action #swagger-api 285 | * 286 | * @function index 287 | * @memberof UserController 288 | * @description #tags user 289 | * @description #produces application/json 290 | * @description #parameters index query schema.definitions.index true - parameter index 291 | * @description #responses 200 schema.user - index response 292 | */ 293 | async index() { 294 | this.ctx.body = 'hi, index action' + this.app.plugins.swaggerEgg.name; 295 | } 296 | 297 | /** 298 | * New action #swagger-api 299 | * 300 | * @function new 301 | * @memberof UserController 302 | * @description #tags user 303 | * @description #consumes application/x-www-form-urlencoded 304 | * @description #produces application/json 305 | * @description #parameters userInfo body schema.user true - parameter userInfo 306 | * @description #responses 200 schema.user - new response 307 | */ 308 | async new() { 309 | this.ctx.body = 'hi, new action' + this.app.plugins.swaggerEgg.name; 310 | } 311 | 312 | /** 313 | * Show action #swagger-api 314 | * 315 | * @function show 316 | * @memberof UserController 317 | * @description #tags user 318 | * @description #produces application/json 319 | * @description #parameters id path schema.definitions.id true - parameter id 320 | * @description #responses 200 schema.user - show response 321 | */ 322 | async show() { 323 | this.ctx.body = 'hi, show action' + this.app.plugins.swaggerEgg.name; 324 | } 325 | 326 | /** 327 | * Edit action #swagger-api 328 | * 329 | * @function edit 330 | * @memberof UserController 331 | * @description #tags user 332 | * @description #consumes application/x-www-form-urlencoded 333 | * @description #produces application/json 334 | * @description #parameters id path schema.definitions.id true - parameter id 335 | * @description #parameters userInfo body schema.user true - parameter userInfo 336 | * @description #responses 200 schema.user - edit response 337 | */ 338 | async edit() { 339 | this.ctx.body = 'hi, edit action ' + this.app.plugins.swaggerEgg.name; 340 | } 341 | 342 | /** 343 | * Create action #swagger-api 344 | * 345 | * @function create 346 | * @memberof UserController 347 | * @description #tags user 348 | * @description #consumes application/x-www-form-urlencoded 349 | * @description #produces application/json 350 | * @description #parameters userInfo body schema.user true - parameter userInfo 351 | * @description #responses 200 schema.user - create response 352 | */ 353 | async create() { 354 | this.ctx.body = 'hi, create action ' + this.app.plugins.swaggerEgg.name; 355 | } 356 | 357 | /** 358 | * Update action #swagger-api 359 | * 360 | * @function update 361 | * @memberof UserController 362 | * @description #tags user 363 | * @description #consumes application/x-www-form-urlencoded 364 | * @description #produces application/json 365 | * @description #parameters id path schema.definitions.id true - parameter id 366 | * @description #parameters userInfo body schema.user true - parameter userInfo 367 | * @description #responses 200 schema.user - update response 368 | */ 369 | async update() { 370 | this.ctx.body = 'hi, update action ' + this.app.plugins.swaggerEgg.name; 371 | } 372 | 373 | /** 374 | * Destory action #swagger-api 375 | * 376 | * @function destory 377 | * @memberof UserController 378 | * @description #tags user 379 | * @description #consumes application/json 380 | * @description #produces application/json 381 | * @description #parameters id path schema.definitions.id false - parameter id 382 | * @description #responses 200 schema.user - destory response 383 | */ 384 | async destory() { 385 | this.ctx.body = 'hi, destory action ' + this.app.plugins.swaggerEgg.name; 386 | } 387 | } 388 | 389 | module.exports = UserController; 390 | 391 | ``` 392 | 393 | ## Questions & Suggestions 394 | 395 | Please open an issue [here](https://github.com/JsonMa/swagger-egg/issues). 396 | 397 | ## License 398 | 399 | [MIT](LICENSE) 400 | -------------------------------------------------------------------------------- /README.zh_CN.md: -------------------------------------------------------------------------------- 1 | # swagger-egg 2 | 3 | ![swagger-egg](https://socialify.git.ci/JsonMa/swagger-egg/image?description=1&font=Inter&forks=1&issues=1&language=1&owner=1&pattern=Floating%20Cogs&pulls=1&stargazers=1&theme=Light) 4 | 5 | [![NPM version][npm-image]][npm-url] 6 | [![build status][travis-image]][travis-url] 7 | [![Test coverage][codecov-image]][codecov-url] 8 | [![David deps][david-image]][david-url] 9 | [![Known Vulnerabilities][snyk-image]][snyk-url] 10 | [![npm download][download-image]][download-url] 11 | 12 | [英文文档](https://github.com/JsonMa/swagger-egg/blob/master/README.md) 13 | 14 | [npm-image]: https://img.shields.io/npm/v/swagger-egg.svg?style=flat-square 15 | [npm-url]: https://npmjs.org/package/swagger-egg 16 | [travis-image]: https://travis-ci.com/JsonMa/swagger-egg.svg?branch=master 17 | [travis-url]: https://travis-ci.org/jsonma/swagger-egg 18 | [codecov-image]: https://img.shields.io/codecov/c/github/jsonma/swagger-egg.svg?style=flat-square 19 | [codecov-url]: https://codecov.io/github/jsonma/swagger-egg?branch=master 20 | [david-image]: https://img.shields.io/david/jsonma/swagger-egg.svg?style=flat-square 21 | [david-url]: https://david-dm.org/jsonma/swagger-egg 22 | [snyk-image]: https://snyk.io/test/npm/swagger-egg/badge.svg?style=flat-square 23 | [snyk-url]: https://snyk.io/test/npm/swagger-egg 24 | [download-image]: https://img.shields.io/npm/dm/swagger-egg.svg?style=flat-square 25 | [download-url]: https://npmjs.org/package/swagger-egg 26 | 27 | 30 | Eggjs [Swagger UI](https://swagger.io/tools/swagger-ui/) API文档自动生成插件(支持Typescript),请求及响应参数需通过[JSON Schema](http://json-schema.org/specification.html)(推荐使用[Ajv](https://github.com/ajv-validator/ajv))定义,并遵循 [Swagger (OpenAPI v2)](https://swagger.io/specification/v2/) 规范,`swagger.json` 由插件通过Controller中的 JSDoc 注释自动生成。 31 | 32 | **注意**: Node.js版本需要>=10.x! 33 | 34 | ## 插件安装 35 | 36 | ```bash 37 | $ npm i swagger-egg --save 38 | ``` 39 | 40 | ## 插件使用 41 | Swagger-UI 以 [egg-static](https://github.com/eggjs/egg-static) 静态资源的形式进行访问,若`static.prefix`为默认值,则只需要打开`http://localhost:7001/public/index.html`即可获取到 Swagger-UI 页面。关于插件在项目中的使用,请参考下面的示例: 42 | 43 | - [JS 项目示例](https://github.com/JsonMa/swagger-egg/tree/master/example/egg-swagger-example) 44 | - [TS 项目示例](https://github.com/JsonMa/swagger-egg/tree/master/example/egg-swagger-ts-example) 45 | - [TS-Json-Schema 项目示例 ](https://github.com/JsonMa/swagger-egg/tree/master/example/egg-swagger-ts-schema-example) 46 | 47 | ```js 48 | // {app_root}/config/plugin.js 49 | exports.swaggerEgg = { 50 | enable: true, 51 | package: "swagger-egg", 52 | }; 53 | ``` 54 | 55 | ## 插件配置 56 | + `swagger.info` 是可选的,若不存在,则插件将会依据根目录下的`package.json`信息自动生成。 57 | + `swagger.tags` 是必选的,如果在JSDoc注释中使用了`#tags`标签。 58 | + 更多Swagger配置请参考[OpenAPI V2](https://swagger.io/specification/v2/)。 59 | 60 | ```js 61 | // {app_root}/config/config.default.js 62 | exports.swaggerEgg = { 63 | schema: { 64 | path: '/app/schema', // JSON Schema directory 65 | }, 66 | swagger: { 67 | info: { 68 | title: 'Test swagger', 69 | description: 'Testing the Fastify swagger API', 70 | version: '0.1.0' 71 | }, 72 | externalDocs: { 73 | url: 'https://swagger.io', 74 | description: 'Find more info here' 75 | }, 76 | host: '127.0.0.1:7001', // 应当与egg server host保持一致,否则会有跨域的问题 77 | schemes: ['http', 'https'], 78 | consumes: ['application/json'], 79 | produces: ['application/json'], 80 | tags: [ 81 | { name: 'user', description: 'User related end-points' } 82 | ], 83 | securityDefinitions: { 84 | api_key: { 85 | type: 'apiKey', // basic/apiKey/oauth2 86 | name: 'Authorization', // 自定义的鉴权参数,通常为'Authorization' 87 | in: 'header', // 鉴权参数放置的位置,query 或者 header 88 | }, 89 | swagger_auth: { 90 | type: 'oauth2', 91 | authorizationUrl: 'http://swagger.io/api/oauth/dialog', 92 | flow: 'implicit', 93 | scopes: { 94 | 'write:homes': 'modify home info', 95 | 'read:homes': 'read home info', 96 | }, 97 | }, 98 | }, 99 | security: [ 100 | { 101 | api_key: [], // 鉴权方式(securityDefinitions中定义的内容) 102 | }, 103 | ], // 注意: security为数组类型 104 | }, 105 | }; 106 | ``` 107 | 108 | 访问 [config/config.default.js](config/config.default.js) 查看更多默认配置。 109 | 110 | ## 插件语法 111 | 112 | ### #swagger-api 113 | JSDoc注释中的`#swagger-api`标签是必须的,插件将以该标签为标识进行注释的自动扫描。 114 | 115 | ```js 116 | /** 117 | * #swagger-api 118 | * 119 | * @function index 120 | */ 121 | async index() { 122 | this.ctx.body = 'hi, #swagger-api example' 123 | } 124 | ``` 125 | 126 | ### @function {Name} 127 | JSDoc注释的 `@function` 标签也是必须的,插件通过函数名去 `app/router.js`中进行扫描,以获取API的`Http Method、Http Url`信息。 128 | 129 | ```js 130 | /** 131 | * Function example #swagger-api 132 | * 133 | * @function index 134 | */ 135 | async index() { 136 | this.ctx.body = 'hi, function example' 137 | } 138 | ``` 139 | ### @summary {functionSummary} 140 | JSDoc `@summary` 用于声明函数的简介. 141 | 142 | ```js 143 | /** 144 | * Function example #swagger-api 145 | * 146 | * @function index 147 | * @summary This is function's summary. 148 | */ 149 | async index() { 150 | this.ctx.body = 'hi, summary example' 151 | } 152 | ``` 153 | ### @description #tags {Tag1} {Tag2} ... 154 | JSDoc `@description`内容中的`#tags`标签用于声明该API用到的Swagger tag。 155 | 156 | 注意: 多个Swagger tags 间应当使用空格进行分隔。 157 | 158 | ```js 159 | /** 160 | * Tags example #swagger-api 161 | * 162 | * @function index 163 | * @description #tags user admin 164 | */ 165 | async index() { 166 | this.ctx.body = 'hi, tags example' 167 | } 168 | ``` 169 | ### @description #produces {Mimetype1} {Mimetype2} ... 170 | JSDoc `@description`内容中的`#produces` 用于声明API Response MIMEtype. 171 | 172 | 注意: 多个MIMEtype使用空格进行分隔。 173 | 174 | ```js 175 | /** 176 | * Produces example #swagger-api 177 | * 178 | * @function index 179 | * @description #produces application/json 180 | */ 181 | async index() { 182 | this.ctx.body = 'hi, produces example' 183 | } 184 | ``` 185 | 186 | ### @description #consumes {Mimetype1} {Mimetype1} ... 187 | 188 | JSDoc `@description`内容中的`#consumes`用于声明API Request MIMEtype. 189 | 190 | 注意: 多个MIMEtype使用空格进行分隔。 191 | 192 | ```js 193 | /** 194 | * Consumes example #swagger-api 195 | * 196 | * @function index 197 | * @description #consumes application/json 198 | */ 199 | async index() { 200 | this.ctx.body = 'hi, consumes example' 201 | } 202 | ``` 203 | 204 | ### @description #parameters {PrameterName} {In} {ParameterSchema|Type} {Required} - {Description} 205 | JSDoc `@description`内容中的`#parameters`用于声明API Request Parameters. 206 | 207 | 注意: description需单独使用` - `分隔开(遵循JSDoc写法)其它参数使用空格进行分隔。 208 | 209 | 注意: 210 | - 按照Swagger规范,变量`In`的取值范围只能为`'query', 'header', 'path', 'formData', 'body'` 211 | - 变量`Required`的值只能为`true`或者`false`。 212 | - 变量`Type`的取值范围只能为`['string', 'number', 'integer', 'boolean', 'array', 'file']`。 213 | 214 | ```js 215 | /** 216 | * Parameters example #swagger-api 217 | * 218 | * @function index 219 | * @description #parameters id path schema.id true - id parameter 220 | */ 221 | async index() { 222 | this.ctx.body = 'hi, parameters example' 223 | } 224 | ``` 225 | 226 | ### @description #responses {HttpStatus} {ResponseSchema} - {Description} 227 | 228 | JSDoc `@description`内容中的`#responses` 用于声明API Response。 229 | 230 | 注意: description需单独使用` - `分隔开(遵循JSDoc写法)其它参数使用空格进行分隔。 231 | 232 | ```js 233 | /** 234 | * Responses example #swagger-api 235 | * 236 | * @function index 237 | * @description #responses schema.user - user responses 238 | */ 239 | async index() { 240 | this.ctx.body = 'hi, responses example' 241 | } 242 | ``` 243 | 244 | ## Schema Example 245 | 246 | Schema的写法需遵循 [JSON Schema](http://json-schema.org/) 规范,推荐使用[Ajv](https://ajv.js.org/guide/getting-started.html) 进行参数校验。 247 | 248 | 更改 `swaggerEgg.schema.path` 字段可制定待扫描的Schema文件路径。 249 | 250 | ```js 251 | // {app_root}/app/schema/users.js 252 | 253 | module.exports = { 254 | type: 'object', 255 | properties: { 256 | id: { 257 | type: 'string', 258 | description: 'user id' 259 | }, 260 | name: { 261 | type: 'string', 262 | description: 'user name' 263 | }, 264 | age: { 265 | type: 'number', 266 | description: 'user age' 267 | }, 268 | }, 269 | required: [ 'id', 'name', 'age' ], 270 | additionalProperties: false, 271 | }; 272 | ``` 273 | 274 | ## Controller 示例 275 | 276 | ```js 277 | // {app_root}/app/controller/users.js 278 | 279 | const Controller = require('egg').Controller; 280 | 281 | class UserController extends Controller { 282 | 283 | /** 284 | * Index action #swagger-api 285 | * 286 | * @function index 287 | * @memberof UserController 288 | * @description #tags user 289 | * @description #produces application/json 290 | * @description #parameters index query schema.definitions.index true - parameter index 291 | * @description #responses 200 schema.user - index response 292 | */ 293 | async index() { 294 | this.ctx.body = 'hi, index action' + this.app.plugins.swaggerEgg.name; 295 | } 296 | 297 | /** 298 | * New action #swagger-api 299 | * 300 | * @function new 301 | * @memberof UserController 302 | * @description #tags user 303 | * @description #consumes application/x-www-form-urlencoded 304 | * @description #produces application/json 305 | * @description #parameters userInfo body schema.user true - parameter userInfo 306 | * @description #responses 200 schema.user - new response 307 | */ 308 | async new() { 309 | this.ctx.body = 'hi, new action' + this.app.plugins.swaggerEgg.name; 310 | } 311 | 312 | /** 313 | * Show action #swagger-api 314 | * 315 | * @function show 316 | * @memberof UserController 317 | * @description #tags user 318 | * @description #produces application/json 319 | * @description #parameters id path schema.definitions.id true - parameter id 320 | * @description #responses 200 schema.user - show response 321 | */ 322 | async show() { 323 | this.ctx.body = 'hi, show action' + this.app.plugins.swaggerEgg.name; 324 | } 325 | 326 | /** 327 | * Edit action #swagger-api 328 | * 329 | * @function edit 330 | * @memberof UserController 331 | * @description #tags user 332 | * @description #consumes application/x-www-form-urlencoded 333 | * @description #produces application/json 334 | * @description #parameters id path schema.definitions.id true - parameter id 335 | * @description #parameters userInfo body schema.user true - parameter userInfo 336 | * @description #responses 200 schema.user - edit response 337 | */ 338 | async edit() { 339 | this.ctx.body = 'hi, edit action ' + this.app.plugins.swaggerEgg.name; 340 | } 341 | 342 | /** 343 | * Create action #swagger-api 344 | * 345 | * @function create 346 | * @memberof UserController 347 | * @description #tags user 348 | * @description #consumes application/x-www-form-urlencoded 349 | * @description #produces application/json 350 | * @description #parameters userInfo body schema.user true - parameter userInfo 351 | * @description #responses 200 schema.user - create response 352 | */ 353 | async create() { 354 | this.ctx.body = 'hi, create action ' + this.app.plugins.swaggerEgg.name; 355 | } 356 | 357 | /** 358 | * Update action #swagger-api 359 | * 360 | * @function update 361 | * @memberof UserController 362 | * @description #tags user 363 | * @description #consumes application/x-www-form-urlencoded 364 | * @description #produces application/json 365 | * @description #parameters id path schema.definitions.id true - parameter id 366 | * @description #parameters userInfo body schema.user true - parameter userInfo 367 | * @description #responses 200 schema.user - update response 368 | */ 369 | async update() { 370 | this.ctx.body = 'hi, update action ' + this.app.plugins.swaggerEgg.name; 371 | } 372 | 373 | /** 374 | * Destory action #swagger-api 375 | * 376 | * @function destory 377 | * @memberof UserController 378 | * @description #tags user 379 | * @description #consumes application/json 380 | * @description #produces application/json 381 | * @description #parameters id path schema.definitions.id false - parameter id 382 | * @description #responses 200 schema.user - destory response 383 | */ 384 | async destory() { 385 | this.ctx.body = 'hi, destory action ' + this.app.plugins.swaggerEgg.name; 386 | } 387 | } 388 | 389 | module.exports = UserController; 390 | 391 | ``` 392 | 393 | ## 问题及建议 394 | 395 | 请创建 [issue](https://github.com/JsonMa/swagger-egg/issues) 来反馈您的问题及建议。同时欢迎更多的小伙伴能奉献一款swagger-egg vscode插件,供大家使用。 396 | 397 | ## License 398 | 399 | [MIT](LICENSE) 400 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const pathToSwaggerUi = require('swagger-ui-dist').absolutePath(); 4 | const Swagger = require('./lib/swagger'); 5 | 6 | class AppBootHook { 7 | constructor(app) { 8 | this.app = app; 9 | } 10 | 11 | configWillLoad() { 12 | let staticDirs = this.app.config.static.dir; 13 | // CAUTION: index.html under 'app/public' directory will be overwrite by 'swagger-ui-dist' 14 | if (Array.isArray(staticDirs)) staticDirs.unshift(pathToSwaggerUi); 15 | else staticDirs = [pathToSwaggerUi, staticDirs]; 16 | this.app.config.static.dir = staticDirs; 17 | } 18 | 19 | didLoad() { 20 | try { 21 | new Swagger(this.app, pathToSwaggerUi); 22 | this.app.logger.info(`[swagger-egg] Swagger document initing succeed!`); 23 | } catch (error) { 24 | this.app.logger.error(`[swagger-egg] ${error.message}`); 25 | } 26 | } 27 | } 28 | 29 | module.exports = AppBootHook; 30 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '8' 4 | - nodejs_version: '10' 5 | 6 | install: 7 | - ps: Install-Product node $env:nodejs_version 8 | - npm i npminstall && node_modules\.bin\npminstall 9 | 10 | test_script: 11 | - node --version 12 | - npm --version 13 | - npm run test 14 | 15 | build: off 16 | -------------------------------------------------------------------------------- /config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * egg-swagger-egg default config 5 | * @member Config#swaggerEgg 6 | * @property {String} SOME_KEY - some description 7 | */ 8 | exports.swaggerEgg = { 9 | schema: { 10 | path: '/app/schema', // JSON Schema directory 11 | }, 12 | swaggerUI: { 13 | deepLinking: true, 14 | docExpansion: 'none', 15 | filter: false, 16 | syntaxHighlight: false, 17 | }, 18 | swagger: { 19 | host: '', 20 | basePath: '/', 21 | schemes: ['https', 'http'], 22 | consumes: ['application/json'], 23 | produces: ['application/json'], 24 | tags: [], 25 | }, 26 | typescriptJsonSchema: false, 27 | }; 28 | -------------------------------------------------------------------------------- /example/egg-swagger-example/.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | prefix: '^', 6 | plugin: 'autod-egg', 7 | test: [ 8 | 'test', 9 | 'benchmark', 10 | ], 11 | dep: [ 12 | 'egg', 13 | 'egg-scripts', 14 | ], 15 | devdep: [ 16 | 'egg-ci', 17 | 'egg-bin', 18 | 'egg-mock', 19 | 'autod', 20 | 'autod-egg', 21 | 'eslint', 22 | 'eslint-config-egg', 23 | ], 24 | exclude: [ 25 | './test/fixtures', 26 | './dist', 27 | ], 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /example/egg-swagger-example/.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | -------------------------------------------------------------------------------- /example/egg-swagger-example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-egg" 3 | } 4 | -------------------------------------------------------------------------------- /example/egg-swagger-example/.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | schedule: 12 | - cron: '0 2 * * *' 13 | 14 | jobs: 15 | build: 16 | runs-on: ${{ matrix.os }} 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | node-version: [10] 22 | os: [ubuntu-latest, windows-latest, macos-latest] 23 | 24 | steps: 25 | - name: Checkout Git Source 26 | uses: actions/checkout@v2 27 | 28 | - name: Use Node.js ${{ matrix.node-version }} 29 | uses: actions/setup-node@v1 30 | with: 31 | node-version: ${{ matrix.node-version }} 32 | 33 | - name: Install Dependencies 34 | run: npm i -g npminstall && npminstall 35 | 36 | - name: Continuous Integration 37 | run: npm run ci 38 | 39 | - name: Code Coverage 40 | uses: codecov/codecov-action@v1 41 | with: 42 | token: ${{ secrets.CODECOV_TOKEN }} 43 | -------------------------------------------------------------------------------- /example/egg-swagger-example/.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | yarn-error.log 4 | node_modules/ 5 | package-lock.json 6 | yarn.lock 7 | coverage/ 8 | .idea/ 9 | run/ 10 | .DS_Store 11 | *.sw* 12 | *.un~ 13 | typings/ 14 | .nyc_output/ 15 | -------------------------------------------------------------------------------- /example/egg-swagger-example/.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: node_js 3 | node_js: 4 | - '10' 5 | before_install: 6 | - npm i npminstall -g 7 | install: 8 | - npminstall 9 | script: 10 | - npm run ci 11 | after_script: 12 | - npminstall codecov && codecov 13 | -------------------------------------------------------------------------------- /example/egg-swagger-example/README.md: -------------------------------------------------------------------------------- 1 | # egg-swagger-example 2 | 3 | This is an egg swagger example. 4 | 5 | ### Usage 6 | 7 | Try the flowing steps and you will get the Swagge-UI page! 8 | 9 | ```bash 10 | $ npm i 11 | $ npm run dev 12 | $ open http://localhost:7001/index.html 13 | ``` 14 | 15 | ### Notes 16 | 17 | `swagger.json` will be injected to your `app/public` direcotry automaticlly by this plugin. -------------------------------------------------------------------------------- /example/egg-swagger-example/app/controller/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Controller = require('egg').Controller; 4 | 5 | class HomeController extends Controller { 6 | 7 | /** 8 | * Index action #swagger-api 9 | * 10 | * @function index 11 | * @memberof HomeController 12 | * @description #tags home 13 | * @description #produces application/json 14 | * @description #parameters index query schema.definitions.id true - index query parameter 15 | * @description #responses 200 schema.home - index response 16 | */ 17 | async index() { 18 | let message = this.app.plugins.swaggerEgg.name; 19 | if (this.ctx.queries.index) message = this.ctx.request.queries.index; 20 | this.ctx.body = { 21 | name: message, 22 | address: 'this is address', 23 | no: 'this is no', 24 | }; 25 | } 26 | 27 | /** 28 | * New action #swagger-api 29 | * 30 | * @function new 31 | * @memberof HomeController 32 | * @description #tags home 33 | * @description #consumes application/x-www-form-urlencoded 34 | * @description #produces application/json 35 | * @description #parameters in body schema.home true - new body parameter 36 | * @description #responses 200 schema.home - new response 37 | */ 38 | async new() { 39 | this.ctx.body = 'hi, new action' + this.app.plugins.swaggerEgg.name; 40 | } 41 | 42 | /** 43 | * Show action #swagger-api 44 | * 45 | * @function show 46 | * @memberof HomeController 47 | * @description #tags home 48 | * @description #produces application/json 49 | * @description #parameters id path schema.definitions.id true - show path parameter 50 | * @description #responses 200 schema.home - show response 51 | */ 52 | async show() { 53 | this.ctx.body = 'hi, show action' + this.app.plugins.swaggerEgg.name; 54 | } 55 | 56 | /** 57 | * Edit action #swagger-api 58 | * 59 | * @function edit 60 | * @memberof HomeController 61 | * @description #tags home 62 | * @description #consumes application/x-www-form-urlencoded 63 | * @description #produces application/json 64 | * @description #parameters id path schema.definitions.id true - edit path parameter 65 | * @description #parameters in body schema.home true - edit body parameter 66 | * @description #responses 200 schema.home - edit response 67 | */ 68 | async edit() { 69 | this.ctx.body = 'hi, edit action ' + this.app.plugins.swaggerEgg.name; 70 | } 71 | 72 | /** 73 | * Create action #swagger-api 74 | * 75 | * @function create 76 | * @memberof HomeController 77 | * @description #tags home 78 | * @description #consumes application/x-www-form-urlencoded 79 | * @description #consumes application/json 80 | * @description #parameters in body schema.home true - create body parameter 81 | * @description #responses 200 schema.home - create response 82 | */ 83 | async create() { 84 | this.ctx.body = 'hi, create action ' + this.app.plugins.swaggerEgg.name; 85 | } 86 | 87 | /** 88 | * Update action #swagger-api 89 | * 90 | * @function update 91 | * @memberof HomeController 92 | * @description #tags home 93 | * @description #consumes application/x-www-form-urlencoded 94 | * @description #produces application/json 95 | * @description #parameters id path schema.definitions.id true - update path parameter 96 | * @description #parameters id body schema.home true - update body parameter 97 | * @description #responses 200 schema.home - update response 98 | */ 99 | async update() { 100 | this.ctx.body = 'hi, update action ' + this.app.plugins.swaggerEgg.name; 101 | } 102 | 103 | /** 104 | * Destory action #swagger-api 105 | * 106 | * @function destory 107 | * @memberof HomeController 108 | * @description #tags home 109 | * @description #consumes application/json 110 | * @description #produces application/json 111 | * @description #parameters id path schema.definitions.id false - destory path parameter 112 | * @description #responses 200 schema.home - destory response 113 | */ 114 | async destory() { 115 | this.ctx.body = 'hi, destory action ' + this.app.plugins.swaggerEgg.name; 116 | } 117 | } 118 | 119 | module.exports = HomeController; 120 | -------------------------------------------------------------------------------- /example/egg-swagger-example/app/public/swagger.json: -------------------------------------------------------------------------------- 1 | {"swagger":"2.0","info":{"title":"Egg Example Swagger Document","description":"Testing the egg example swagger API","version":"1.0.0"},"tags":[{"name":"home","description":"Home related end-points"}],"definitions":{"id":{"type":"string"},"index":{"type":"string"},"no":{"type":"string"}},"paths":{"/":{"get":{"description":"Index action","parameters":[{"name":"index","required":true,"description":"index query parameter","in":"query","type":"string"}],"responses":{"200":{"description":"index response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}},"tags":["home"],"produces":["application/json"]}},"/homes/new":{"get":{"description":"New action","parameters":[{"name":"in","required":true,"description":"new body parameter","in":"body","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}],"responses":{"200":{"description":"new response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}},"tags":["home"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]}},"/homes/:id":{"get":{"description":"Show action","parameters":[{"name":"id","required":true,"description":"show path parameter","in":"path","type":"string"}],"responses":{"200":{"description":"show response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}},"tags":["home"],"produces":["application/json"]},"put":{"description":"Update action","parameters":[{"name":"id","required":true,"description":"update path parameter","in":"path","type":"string"},{"name":"id","required":true,"description":"update body parameter","in":"body","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}],"responses":{"200":{"description":"update response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}},"tags":["home"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]},"delete":{"description":"Destory action","parameters":[{"name":"id","required":false,"description":"destory path parameter","in":"path","type":"string"}],"responses":{"200":{"description":"destory response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}},"tags":["home"],"consumes":["application/json"],"produces":["application/json"]}},"/homes/:id/edit":{"get":{"description":"Edit action","parameters":[{"name":"id","required":true,"description":"edit path parameter","in":"path","type":"string"},{"name":"in","required":true,"description":"edit body parameter","in":"body","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}],"responses":{"200":{"description":"edit response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}},"tags":["home"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]}},"/homes":{"post":{"description":"Create action","parameters":[{"name":"in","required":true,"description":"create body parameter","in":"body","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}],"responses":{"200":{"description":"create response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}},"tags":["home"],"consumes":["application/json"]}}},"host":"127.0.0.1:7001","schemes":["http","https"],"basePath":"/","consumes":["application/json"],"produces":["application/json"],"securityDefinitions":{"api_key":{"type":"apiKey","name":"Authorization","in":"header"},"github_auth":{"type":"oauth2","authorizationUrl":"http://swagger.io/api/oauth/dialog","flow":"implicit","scopes":{"write:homes":"modify home info","read:homes":"read home info"}}},"security":[{"api_key":[]}],"externalDocs":{"url":"https://swagger.io","description":"Find more info here"}} -------------------------------------------------------------------------------- /example/egg-swagger-example/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @param {Egg.Application} app - egg application 5 | */ 6 | module.exports = app => { 7 | const { router, controller } = app; 8 | router.get('/', controller.home.index); 9 | router.get('/homes/new', controller.home.new); 10 | router.get('/homes/:id', controller.home.show); 11 | router.get('/homes/:id/edit', controller.home.edit); 12 | router.post('/homes', controller.home.create); 13 | router.put('/homes/:id', controller.home.update); 14 | router.delete('/homes/:id', controller.home.destory); 15 | }; 16 | -------------------------------------------------------------------------------- /example/egg-swagger-example/app/schema/definitions/id.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | type: 'string', 5 | }; 6 | -------------------------------------------------------------------------------- /example/egg-swagger-example/app/schema/definitions/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | type: 'string', 5 | }; 6 | -------------------------------------------------------------------------------- /example/egg-swagger-example/app/schema/definitions/no.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | type: 'string', 5 | }; 6 | -------------------------------------------------------------------------------- /example/egg-swagger-example/app/schema/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | type: 'object', 5 | properties: { 6 | name: { 7 | type: 'string', 8 | }, 9 | address: { 10 | type: 'string', 11 | }, 12 | no: { 13 | $ref: '#/definitions/no', 14 | }, 15 | }, 16 | required: [ 'name', 'address', 'no' ], 17 | additionalProperties: false, 18 | }; 19 | -------------------------------------------------------------------------------- /example/egg-swagger-example/appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '10' 4 | 5 | install: 6 | - ps: Install-Product node $env:nodejs_version 7 | - npm i npminstall && node_modules\.bin\npminstall 8 | 9 | test_script: 10 | - node --version 11 | - npm --version 12 | - npm run test 13 | 14 | build: off 15 | -------------------------------------------------------------------------------- /example/egg-swagger-example/config/config.default.js: -------------------------------------------------------------------------------- 1 | /* eslint valid-jsdoc: "off" */ 2 | 3 | 'use strict'; 4 | 5 | /** 6 | * @param {Egg.EggAppInfo} appInfo app info 7 | */ 8 | module.exports = appInfo => { 9 | /** 10 | * built-in config 11 | * @type {Egg.EggAppConfig} 12 | **/ 13 | const config = exports = {}; 14 | 15 | // use for cookie sign key, should change to your own and keep security 16 | config.keys = appInfo.name + '_1624498627486_7869'; 17 | 18 | // add your middleware config here 19 | config.middleware = []; 20 | 21 | // add your user config here 22 | // myAppName: 'egg', 23 | // {app_root}/config/config.default.js 24 | config.swaggerEgg = { 25 | schema: { 26 | path: '/app/schema', // JSON Schema directory 27 | }, 28 | swagger: { 29 | info: { 30 | title: 'Egg Example Swagger Document', 31 | description: 'Testing the egg example swagger API', 32 | version: '1.0.0', 33 | }, 34 | externalDocs: { 35 | url: 'https://swagger.io', 36 | description: 'Find more info here', 37 | }, 38 | host: '127.0.0.1:7001', // catution: 'localhost:7001' will result in cross origin error 39 | schemes: [ 'http', 'https' ], 40 | consumes: [ 'application/json' ], 41 | produces: [ 'application/json' ], 42 | tags: [ 43 | { name: 'home', description: 'Home related end-points' }, 44 | ], 45 | securityDefinitions: { 46 | api_key: { 47 | type: 'apiKey', // basic/apiKey/oauth2 48 | name: 'Authorization', // selfdefined parameter, usually use 'Authorization' 49 | in: 'header', // query or header, usually use 'header' 50 | }, 51 | github_auth: { 52 | type: 'oauth2', 53 | authorizationUrl: 'http://swagger.io/api/oauth/dialog', 54 | flow: 'implicit', 55 | scopes: { 56 | 'write:homes': 'modify home info', 57 | 'read:homes': 'read home info', 58 | }, 59 | }, 60 | }, 61 | security: [ 62 | { 63 | api_key: [], // use api key to security 64 | }, 65 | ], // Cacution: security is array type 66 | }, 67 | }; 68 | 69 | return config; 70 | }; 71 | -------------------------------------------------------------------------------- /example/egg-swagger-example/config/plugin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** @type Egg.EggPlugin */ 4 | module.exports = { 5 | // had enabled by egg 6 | static: { 7 | enable: true, 8 | }, 9 | swaggerEgg: { 10 | enable: true, 11 | package: 'swagger-egg', 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /example/egg-swagger-example/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "**/*" 4 | ] 5 | } -------------------------------------------------------------------------------- /example/egg-swagger-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "egg-swagger-example", 3 | "version": "1.0.0", 4 | "description": "egg swagger example", 5 | "private": true, 6 | "egg": { 7 | "declarations": true 8 | }, 9 | "dependencies": { 10 | "egg": "^2.15.1", 11 | "egg-scripts": "^2.11.0", 12 | "swagger-egg": "^1.2.0" 13 | }, 14 | "devDependencies": { 15 | "autod": "^3.0.1", 16 | "autod-egg": "^1.1.0", 17 | "egg-bin": "^4.11.0", 18 | "egg-ci": "^1.11.0", 19 | "egg-mock": "^3.21.0", 20 | "eslint": "^5.13.0", 21 | "eslint-config-egg": "^7.1.0" 22 | }, 23 | "engines": { 24 | "node": ">=10.0.0" 25 | }, 26 | "scripts": { 27 | "start": "egg-scripts start --daemon --title=egg-server-egg-swagger-example", 28 | "stop": "egg-scripts stop --title=egg-server-egg-swagger-example", 29 | "dev": "egg-bin dev", 30 | "debug": "egg-bin debug", 31 | "test": "npm run lint -- --fix && npm run test-local", 32 | "test-local": "egg-bin test", 33 | "cov": "egg-bin cov", 34 | "lint": "eslint .", 35 | "ci": "npm run lint && npm run cov", 36 | "autod": "autod" 37 | }, 38 | "ci": { 39 | "version": "10" 40 | }, 41 | "repository": { 42 | "type": "git", 43 | "url": "" 44 | }, 45 | "author": "jsonma", 46 | "license": "MIT" 47 | } 48 | -------------------------------------------------------------------------------- /example/egg-swagger-example/test/app/controller/home.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { app, assert } = require('egg-mock/bootstrap'); 4 | 5 | describe('test/app/controller/home.test.js', () => { 6 | it('should assert', () => { 7 | const pkg = require('../../../package.json'); 8 | assert(app.config.keys.startsWith(pkg.name)); 9 | 10 | // const ctx = app.mockContext({}); 11 | // yield ctx.service.xx(); 12 | }); 13 | 14 | it('should GET /', () => { 15 | return app.httpRequest() 16 | .get('/') 17 | .expect('hi, egg') 18 | .expect(200); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | plugin: 'autod-egg', 6 | prefix: '^', 7 | devprefix: '^', 8 | exclude: [ 9 | 'test/fixtures', 10 | 'coverage', 11 | ], 12 | dep: [ 13 | 'egg', 14 | 'egg-scripts', 15 | ], 16 | devdep: [ 17 | 'autod', 18 | 'autod-egg', 19 | 'egg-bin', 20 | 'tslib', 21 | 'typescript', 22 | ], 23 | keep: [ 24 | ], 25 | semver: [ 26 | ], 27 | test: 'scripts', 28 | }; 29 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.d.ts 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-egg/typescript", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | } 6 | } -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | - master 11 | pull_request: 12 | branches: 13 | - main 14 | - master 15 | schedule: 16 | - cron: '0 2 * * *' 17 | 18 | jobs: 19 | build: 20 | runs-on: ${{ matrix.os }} 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | node-version: [8] 26 | os: [ubuntu-latest, windows-latest, macos-latest] 27 | 28 | steps: 29 | - name: Checkout Git Source 30 | uses: actions/checkout@v2 31 | 32 | - name: Use Node.js ${{ matrix.node-version }} 33 | uses: actions/setup-node@v1 34 | with: 35 | node-version: ${{ matrix.node-version }} 36 | 37 | - name: Install Dependencies 38 | run: npm i -g npminstall && npminstall 39 | 40 | - name: Continuous Integration 41 | run: npm run ci 42 | 43 | - name: Code Coverage 44 | uses: codecov/codecov-action@v1 45 | with: 46 | token: ${{ secrets.CODECOV_TOKEN }} 47 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | node_modules/ 4 | coverage/ 5 | .idea/ 6 | run/ 7 | logs/ 8 | .DS_Store 9 | .vscode 10 | *.swp 11 | *.lock 12 | *.js 13 | !.autod.conf.js 14 | 15 | app/**/*.js 16 | test/**/*.js 17 | config/**/*.js 18 | app/**/*.map 19 | test/**/*.map 20 | config/**/*.map 21 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: node_js 3 | node_js: 4 | - '8' 5 | before_install: 6 | - npm i npminstall -g 7 | install: 8 | - npminstall 9 | script: 10 | - npm run ci 11 | after_script: 12 | - npminstall codecov && codecov 13 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/README.md: -------------------------------------------------------------------------------- 1 | # hackernews-async-ts 2 | 3 | [Hacker News](https://news.ycombinator.com/) showcase using typescript && egg 4 | 5 | ## QuickStart 6 | 7 | ### Development 8 | 9 | ```bash 10 | $ npm i 11 | $ npm run dev 12 | $ open http://localhost:7001/ 13 | ``` 14 | 15 | Don't tsc compile at development mode, if you had run `tsc` then you need to `npm run clean` before `npm run dev`. 16 | 17 | ### Deploy 18 | 19 | ```bash 20 | $ npm run tsc 21 | $ npm start 22 | ``` 23 | 24 | ### Npm Scripts 25 | 26 | - Use `npm run lint` to check code style 27 | - Use `npm test` to run unit test 28 | - se `npm run clean` to clean compiled js at development mode once 29 | 30 | ### Requirement 31 | 32 | - Node.js 8.x 33 | - Typescript 2.8+ 34 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/app/controller/home.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from 'egg'; 2 | 3 | export default class HomeController extends Controller { 4 | /** 5 | * Index action #swagger-api 6 | * 7 | * @function index 8 | * @memberof HomeController 9 | * @description #tags home 10 | * @description #produces application/json 11 | * @description #parameters index query schema.definitions.id true - index query parameter 12 | * @description #responses 200 schema.home - index response 13 | */ 14 | public async index() { 15 | const { ctx } = this; 16 | ctx.body = await ctx.service.test.sayHi('egg'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/app/public/swagger.json: -------------------------------------------------------------------------------- 1 | {"swagger":"2.0","info":{"title":"Test swagger","description":"Testing the Fastify swagger API","version":"0.1.0"},"tags":[{"name":"home","description":"Home related end-points"}],"definitions":{"id":{"type":"string"},"index":{"type":"string"},"no":{"type":"string"}},"paths":{"/":{"get":{"description":"Index action","operationId":"home/index","parameters":[{"name":"index","required":true,"description":"index query parameter","in":"query","type":"string"}],"responses":{"200":{"description":"index response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"$ref":"#/definitions/no"}},"required":["name","address","no"],"additionalProperties":false}}},"tags":["home"],"produces":["application/json"]}}},"host":"127.0.0.1:7001","schemes":["http","https"],"basePath":"/","consumes":["application/json"],"produces":["application/json"],"securityDefinitions":{"api_key":{"type":"apiKey","name":"Authorization","in":"header"},"github_auth":{"type":"oauth2","authorizationUrl":"http://swagger.io/api/oauth/dialog","flow":"implicit","scopes":{"write:homes":"modify home info","read:homes":"read home info"}}},"security":[{"api_key":[]}],"externalDocs":{"url":"https://swagger.io","description":"Find more info here"}} -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/app/router.ts: -------------------------------------------------------------------------------- 1 | import { Application } from 'egg'; 2 | 3 | export default (app: Application) => { 4 | const { controller, router } = app; 5 | 6 | router.get('/', controller.home.index); 7 | }; 8 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/app/schema/definitions/id.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | type: 'string', 3 | }; 4 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/app/schema/definitions/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | type: 'string', 4 | }; 5 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/app/schema/definitions/no.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | type: 'string', 3 | }; 4 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/app/schema/home.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | type: 'object', 3 | properties: { 4 | name: { 5 | type: 'string', 6 | }, 7 | address: { 8 | type: 'string', 9 | }, 10 | no: { 11 | $ref: '#/definitions/no', 12 | }, 13 | }, 14 | required: [ 'name', 'address', 'no' ], 15 | additionalProperties: false, 16 | }; 17 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/app/service/Test.ts: -------------------------------------------------------------------------------- 1 | import { Service } from 'egg'; 2 | 3 | /** 4 | * Test Service 5 | */ 6 | export default class Test extends Service { 7 | 8 | /** 9 | * sayHi to you 10 | * @param name - your name 11 | */ 12 | public async sayHi(name: string) { 13 | return `hi, ${name}`; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '8' 4 | 5 | install: 6 | - ps: Install-Product node $env:nodejs_version 7 | - npm i npminstall && node_modules\.bin\npminstall 8 | 9 | test_script: 10 | - node --version 11 | - npm --version 12 | - npm run test 13 | 14 | build: off 15 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/config/config.default.ts: -------------------------------------------------------------------------------- 1 | import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg'; 2 | 3 | export default (appInfo: EggAppInfo) => { 4 | const config = {} as PowerPartial; 5 | 6 | // override config from framework / plugin 7 | // use for cookie sign key, should change to your own and keep security 8 | config.keys = appInfo.name + '_1646881464713_4943'; 9 | 10 | // add your egg config in here 11 | config.middleware = []; 12 | 13 | // add your special config in here 14 | const bizConfig = { 15 | sourceUrl: `https://github.com/eggjs/examples/tree/master/${appInfo.name}`, 16 | swaggerEgg: { 17 | schema: { 18 | path: '/app/schema', // JSON Schema directory 19 | }, 20 | swagger: { 21 | info: { 22 | title: 'Test swagger', 23 | description: 'Testing the Fastify swagger API', 24 | version: '0.1.0' 25 | }, 26 | externalDocs: { 27 | url: 'https://swagger.io', 28 | description: 'Find more info here' 29 | }, 30 | host: '127.0.0.1:7001', // should be egg server's host, otherwise result in cross origin error 31 | schemes: ['http', 'https'], 32 | consumes: ['application/json'], 33 | produces: ['application/json'], 34 | tags: [ 35 | { name: 'home', description: 'Home related end-points' } 36 | ], 37 | securityDefinitions: { 38 | api_key: { 39 | type: 'apiKey', // basic/apiKey/oauth2 40 | name: 'Authorization', // selfdefined parameter, usually use 'Authorization' 41 | in: 'header', // query or header, usually use 'header' 42 | }, 43 | github_auth: { 44 | type: 'oauth2', 45 | authorizationUrl: 'http://swagger.io/api/oauth/dialog', 46 | flow: 'implicit', 47 | scopes: { 48 | 'write:homes': 'modify home info', 49 | 'read:homes': 'read home info', 50 | }, 51 | }, 52 | }, 53 | security: [ 54 | { 55 | api_key: [], // select 'api_key' to security(defined in `securityDefinitions`) 56 | }, 57 | ], // Cacution: security is array type 58 | }, 59 | } 60 | } 61 | 62 | // the return config will combines to EggAppConfig 63 | return { 64 | ...config, 65 | ...bizConfig, 66 | }; 67 | }; 68 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/config/config.local.ts: -------------------------------------------------------------------------------- 1 | import { EggAppConfig, PowerPartial } from 'egg'; 2 | 3 | export default () => { 4 | const config: PowerPartial = {}; 5 | return config; 6 | }; 7 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/config/config.prod.ts: -------------------------------------------------------------------------------- 1 | import { EggAppConfig, PowerPartial } from 'egg'; 2 | 3 | export default () => { 4 | const config: PowerPartial = {}; 5 | return config; 6 | }; 7 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/config/plugin.ts: -------------------------------------------------------------------------------- 1 | import { EggPlugin } from 'egg'; 2 | 3 | const plugin: EggPlugin = { 4 | swaggerEgg: { 5 | enable: true, 6 | package: "swagger-egg", 7 | } 8 | }; 9 | 10 | export default plugin; 11 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swagger-ts-example", 3 | "version": "1.0.0", 4 | "description": "swagger egg ts example", 5 | "private": true, 6 | "egg": { 7 | "typescript": true, 8 | "declarations": true 9 | }, 10 | "scripts": { 11 | "start": "egg-scripts start --daemon --title=egg-server-swagger-ts-example", 12 | "stop": "egg-scripts stop --title=egg-server-swagger-ts-example", 13 | "dev": "egg-bin dev", 14 | "debug": "egg-bin debug", 15 | "test-local": "egg-bin test", 16 | "test": "npm run lint -- --fix && npm run test-local", 17 | "cov": "egg-bin cov", 18 | "tsc": "ets && tsc -p tsconfig.json", 19 | "ci": "npm run lint && npm run cov && npm run tsc", 20 | "autod": "autod", 21 | "lint": "eslint . --ext .ts", 22 | "clean": "ets clean" 23 | }, 24 | "dependencies": { 25 | "egg": "^2.6.1", 26 | "egg-scripts": "^2.6.0", 27 | "swagger-egg": "^1.5.0" 28 | }, 29 | "devDependencies": { 30 | "@types/mocha": "^2.2.40", 31 | "@types/node": "^7.0.12", 32 | "@types/supertest": "^2.0.0", 33 | "autod": "^3.0.1", 34 | "autod-egg": "^1.1.0", 35 | "egg-ci": "^1.8.0", 36 | "egg-bin": "^4.11.0", 37 | "egg-mock": "^3.16.0", 38 | "tslib": "^1.9.0", 39 | "eslint": "^6.7.2", 40 | "eslint-config-egg": "^8.0.0", 41 | "typescript": "^3.0.0" 42 | }, 43 | "engines": { 44 | "node": ">=8.9.0" 45 | }, 46 | "ci": { 47 | "version": "8" 48 | }, 49 | "repository": { 50 | "type": "git", 51 | "url": "" 52 | }, 53 | "eslintIgnore": [ 54 | "coverage" 55 | ], 56 | "author": "jsonma", 57 | "license": "MIT" 58 | } 59 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/test/app/controller/home.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import { app } from 'egg-mock/bootstrap'; 3 | 4 | describe('test/app/controller/home.test.ts', () => { 5 | it('should GET /', async () => { 6 | const result = await app.httpRequest().get('/').expect(200); 7 | assert(result.text === 'hi, egg'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/test/app/service/Test.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import { Context } from 'egg'; 3 | import { app } from 'egg-mock/bootstrap'; 4 | 5 | describe('test/app/service/Test.test.js', () => { 6 | let ctx: Context; 7 | 8 | before(async () => { 9 | ctx = app.mockContext(); 10 | }); 11 | 12 | it('sayHi', async () => { 13 | const result = await ctx.service.test.sayHi('egg'); 14 | assert(result === 'hi, egg'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "target": "es2017", 5 | "module": "commonjs", 6 | "strict": true, 7 | "noImplicitAny": false, 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "charset": "utf8", 11 | "allowJs": false, 12 | "pretty": true, 13 | "noEmitOnError": false, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "allowUnreachableCode": false, 17 | "allowUnusedLabels": false, 18 | "strictPropertyInitialization": false, 19 | "noFallthroughCasesInSwitch": true, 20 | "skipLibCheck": true, 21 | "skipDefaultLibCheck": true, 22 | "inlineSourceMap": true, 23 | "importHelpers": true 24 | }, 25 | "exclude": [ 26 | "app/public", 27 | "app/views", 28 | "node_modules*" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/typings/app/controller/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | import ExportHome from '../../../app/controller/home'; 6 | 7 | declare module 'egg' { 8 | interface IController { 9 | home: ExportHome; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/typings/app/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | export * from 'egg'; 6 | export as namespace Egg; 7 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/typings/app/service/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | type AnyClass = new (...args: any[]) => any; 6 | type AnyFunc = (...args: any[]) => T; 7 | type CanExportFunc = AnyFunc> | AnyFunc>; 8 | type AutoInstanceType : T> = U extends AnyClass ? InstanceType : U; 9 | import ExportTest from '../../../app/service/Test'; 10 | 11 | declare module 'egg' { 12 | interface IService { 13 | test: AutoInstanceType; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/typings/config/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | import { EggAppConfig } from 'egg'; 6 | import ExportConfigDefault from '../../config/config.default'; 7 | type ConfigDefault = ReturnType; 8 | type NewEggAppConfig = ConfigDefault; 9 | declare module 'egg' { 10 | interface EggAppConfig extends NewEggAppConfig { } 11 | } -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/typings/config/plugin.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import 'swagger-egg'; 18 | import { EggPluginItem } from 'egg'; 19 | declare module 'egg' { 20 | interface EggPlugin { 21 | onerror?: EggPluginItem; 22 | session?: EggPluginItem; 23 | i18n?: EggPluginItem; 24 | watcher?: EggPluginItem; 25 | multipart?: EggPluginItem; 26 | security?: EggPluginItem; 27 | development?: EggPluginItem; 28 | logrotator?: EggPluginItem; 29 | schedule?: EggPluginItem; 30 | static?: EggPluginItem; 31 | jsonp?: EggPluginItem; 32 | view?: EggPluginItem; 33 | swaggerEgg?: EggPluginItem; 34 | } 35 | } -------------------------------------------------------------------------------- /example/egg-swagger-ts-example/typings/index.d.ts: -------------------------------------------------------------------------------- 1 | import 'egg'; 2 | 3 | declare module 'egg' { 4 | 5 | } -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | plugin: 'autod-egg', 6 | prefix: '^', 7 | devprefix: '^', 8 | exclude: [ 9 | 'test/fixtures', 10 | 'coverage', 11 | ], 12 | dep: [ 13 | 'egg', 14 | 'egg-scripts', 15 | ], 16 | devdep: [ 17 | 'autod', 18 | 'autod-egg', 19 | 'egg-bin', 20 | 'tslib', 21 | 'typescript', 22 | ], 23 | keep: [ 24 | ], 25 | semver: [ 26 | ], 27 | test: 'scripts', 28 | }; 29 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.d.ts 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-egg/typescript", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | } 6 | } -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | - master 11 | pull_request: 12 | branches: 13 | - main 14 | - master 15 | schedule: 16 | - cron: '0 2 * * *' 17 | 18 | jobs: 19 | build: 20 | runs-on: ${{ matrix.os }} 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | node-version: [8] 26 | os: [ubuntu-latest, windows-latest, macos-latest] 27 | 28 | steps: 29 | - name: Checkout Git Source 30 | uses: actions/checkout@v2 31 | 32 | - name: Use Node.js ${{ matrix.node-version }} 33 | uses: actions/setup-node@v1 34 | with: 35 | node-version: ${{ matrix.node-version }} 36 | 37 | - name: Install Dependencies 38 | run: npm i -g npminstall && npminstall 39 | 40 | - name: Continuous Integration 41 | run: npm run ci 42 | 43 | - name: Code Coverage 44 | uses: codecov/codecov-action@v1 45 | with: 46 | token: ${{ secrets.CODECOV_TOKEN }} 47 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | node_modules/ 4 | coverage/ 5 | .idea/ 6 | run/ 7 | logs/ 8 | .DS_Store 9 | .vscode 10 | *.swp 11 | *.lock 12 | *.js 13 | !.autod.conf.js 14 | 15 | app/**/*.js 16 | test/**/*.js 17 | config/**/*.js 18 | app/**/*.map 19 | test/**/*.map 20 | config/**/*.map 21 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: node_js 3 | node_js: 4 | - '8' 5 | before_install: 6 | - npm i npminstall -g 7 | install: 8 | - npminstall 9 | script: 10 | - npm run ci 11 | after_script: 12 | - npminstall codecov && codecov 13 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/README.md: -------------------------------------------------------------------------------- 1 | # hackernews-async-ts 2 | 3 | [Hacker News](https://news.ycombinator.com/) showcase using typescript && egg 4 | 5 | ## QuickStart 6 | 7 | ### Development 8 | 9 | ```bash 10 | $ npm i 11 | $ npm run dev 12 | $ open http://localhost:7001/ 13 | ``` 14 | 15 | Don't tsc compile at development mode, if you had run `tsc` then you need to `npm run clean` before `npm run dev`. 16 | 17 | ### Deploy 18 | 19 | ```bash 20 | $ npm run tsc 21 | $ npm start 22 | ``` 23 | 24 | ### Npm Scripts 25 | 26 | - Use `npm run lint` to check code style 27 | - Use `npm test` to run unit test 28 | - se `npm run clean` to clean compiled js at development mode once 29 | 30 | ### Requirement 31 | 32 | - Node.js 8.x 33 | - Typescript 2.8+ 34 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/app/controller/home.ts: -------------------------------------------------------------------------------- 1 | import {Controller} from 'egg'; 2 | 3 | export default class HomeController extends Controller { 4 | /** 5 | * Index action #swagger-api 6 | * 7 | * @function index 8 | * @memberof HomeController 9 | * @description #tags home 10 | * @description #produces application/json 11 | * @description #parameters index query schema.Id true - index query parameter 12 | * @description #responses 200 schema.home.HomeRes - index response 13 | * @description #responses 400 schema.home.HomeError - index response 14 | */ 15 | public async index() { 16 | const {ctx} = this; 17 | ctx.body = await ctx.service.test.sayHi('egg'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/app/public/swagger.json: -------------------------------------------------------------------------------- 1 | {"swagger":"2.0","info":{"title":"Test swagger","description":"Testing the Fastify swagger API","version":"0.1.0"},"tags":[{"name":"home","description":"Home related end-points"}],"definitions":{"Index":{"type":"string"},"Id":{"type":"string"},"No":{"type":"string"},"CommonResponse":{"type":"object","properties":{"code":{"type":"number"},"msg":{"type":"string"},"data":{"$ref":"#/definitions/T"}},"required":["code","data","msg"]},"HomeRes":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["address","name","no"]},"HomeError":{"type":"object","properties":{"code":{"type":"number"},"msg":{"type":"string"},"data":{"type":"object","properties":{"name":{"type":"string"},"id":{"type":"string"}},"required":["id","name"]}},"required":["code","data","msg"]},"T":{"type":"object"}},"paths":{"/":{"get":{"description":"Index action","operationId":"home/index","parameters":[{"name":"index","required":true,"description":"index query parameter","in":"query","type":"string"}],"responses":{"200":{"description":"index response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["address","name","no"]}},"400":{"description":"index response","schema":{"type":"object","properties":{"code":{"type":"number"},"msg":{"type":"string"},"data":{"type":"object","properties":{"name":{"type":"string"},"id":{"type":"string"}},"required":["id","name"]}},"required":["code","data","msg"]}}},"tags":["home"],"produces":["application/json"]}}},"host":"127.0.0.1:7001","schemes":["http","https"],"basePath":"/","consumes":["application/json"],"produces":["application/json"],"securityDefinitions":{"api_key":{"type":"apiKey","name":"Authorization","in":"header"},"github_auth":{"type":"oauth2","authorizationUrl":"http://swagger.io/api/oauth/dialog","flow":"implicit","scopes":{"write:homes":"modify home info","read:homes":"read home info"}}},"security":[{"api_key":[]}],"externalDocs":{"url":"https://swagger.io","description":"Find more info here"}} -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/app/router.ts: -------------------------------------------------------------------------------- 1 | import { Application } from 'egg'; 2 | 3 | export default (app: Application) => { 4 | const { controller, router } = app; 5 | 6 | router.get('/', controller.home.index); 7 | }; 8 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/app/schema/definitions/Index.ts: -------------------------------------------------------------------------------- 1 | export type Index = string; 2 | export type Id = string; 3 | export type No = string; 4 | 5 | export interface CommonResponse { 6 | code: number; 7 | msg: string; 8 | data: T; 9 | } 10 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/app/schema/home.ts: -------------------------------------------------------------------------------- 1 | import {No, CommonResponse, Id} from './definitions'; 2 | 3 | export interface HomeRes { 4 | name: string; 5 | address: string; 6 | no: No; 7 | } 8 | 9 | export type HomeError = CommonResponse<{ 10 | name: string; 11 | id: Id; 12 | }>; 13 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/app/service/Test.ts: -------------------------------------------------------------------------------- 1 | import { Service } from 'egg'; 2 | 3 | /** 4 | * Test Service 5 | */ 6 | export default class Test extends Service { 7 | 8 | /** 9 | * sayHi to you 10 | * @param name - your name 11 | */ 12 | public async sayHi(name: string) { 13 | return `hi, ${name}`; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '8' 4 | 5 | install: 6 | - ps: Install-Product node $env:nodejs_version 7 | - npm i npminstall && node_modules\.bin\npminstall 8 | 9 | test_script: 10 | - node --version 11 | - npm --version 12 | - npm run test 13 | 14 | build: off 15 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/config/config.default.ts: -------------------------------------------------------------------------------- 1 | import {EggAppConfig, EggAppInfo, PowerPartial} from 'egg'; 2 | 3 | export default (appInfo: EggAppInfo) => { 4 | const config = {} as PowerPartial; 5 | 6 | // override config from framework / plugin 7 | // use for cookie sign key, should change to your own and keep security 8 | config.keys = appInfo.name + '_1646881464713_4943'; 9 | 10 | // add your egg config in here 11 | config.middleware = []; 12 | 13 | // add your special config in here 14 | const bizConfig = { 15 | sourceUrl: `https://github.com/eggjs/examples/tree/master/${appInfo.name}`, 16 | swaggerEgg: { 17 | schema: { 18 | path: '/app/schema', // JSON Schema directory 19 | }, 20 | typescriptJsonSchema: true, 21 | swagger: { 22 | info: { 23 | title: 'Test swagger', 24 | description: 'Testing the Fastify swagger API', 25 | version: '0.1.0', 26 | }, 27 | externalDocs: { 28 | url: 'https://swagger.io', 29 | description: 'Find more info here', 30 | }, 31 | host: '127.0.0.1:7001', // should be egg server's host, otherwise result in cross origin error 32 | schemes: ['http', 'https'], 33 | consumes: ['application/json'], 34 | produces: ['application/json'], 35 | tags: [{name: 'home', description: 'Home related end-points'}], 36 | securityDefinitions: { 37 | api_key: { 38 | type: 'apiKey', // basic/apiKey/oauth2 39 | name: 'Authorization', // selfdefined parameter, usually use 'Authorization' 40 | in: 'header', // query or header, usually use 'header' 41 | }, 42 | github_auth: { 43 | type: 'oauth2', 44 | authorizationUrl: 'http://swagger.io/api/oauth/dialog', 45 | flow: 'implicit', 46 | scopes: { 47 | 'write:homes': 'modify home info', 48 | 'read:homes': 'read home info', 49 | }, 50 | }, 51 | }, 52 | security: [ 53 | { 54 | api_key: [], // select 'api_key' to security(defined in `securityDefinitions`) 55 | }, 56 | ], // Cacution: security is array type 57 | }, 58 | }, 59 | }; 60 | 61 | // the return config will combines to EggAppConfig 62 | return { 63 | ...config, 64 | ...bizConfig, 65 | }; 66 | }; 67 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/config/config.local.ts: -------------------------------------------------------------------------------- 1 | import { EggAppConfig, PowerPartial } from 'egg'; 2 | 3 | export default () => { 4 | const config: PowerPartial = {}; 5 | return config; 6 | }; 7 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/config/config.prod.ts: -------------------------------------------------------------------------------- 1 | import { EggAppConfig, PowerPartial } from 'egg'; 2 | 3 | export default () => { 4 | const config: PowerPartial = {}; 5 | return config; 6 | }; 7 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/config/plugin.ts: -------------------------------------------------------------------------------- 1 | import { EggPlugin } from 'egg'; 2 | 3 | const plugin: EggPlugin = { 4 | swaggerEgg: { 5 | enable: true, 6 | package: "swagger-egg", 7 | } 8 | }; 9 | 10 | export default plugin; 11 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swagger-ts-example", 3 | "version": "1.0.0", 4 | "description": "swagger egg ts example", 5 | "private": true, 6 | "egg": { 7 | "typescript": true, 8 | "declarations": true 9 | }, 10 | "scripts": { 11 | "start": "egg-scripts start --daemon --title=egg-server-swagger-ts-example", 12 | "stop": "egg-scripts stop --title=egg-server-swagger-ts-example", 13 | "dev": "egg-bin dev", 14 | "debug": "egg-bin debug", 15 | "test-local": "egg-bin test", 16 | "test": "npm run lint -- --fix && npm run test-local", 17 | "cov": "egg-bin cov", 18 | "tsc": "ets && tsc -p tsconfig.json", 19 | "ci": "npm run lint && npm run cov && npm run tsc", 20 | "autod": "autod", 21 | "lint": "eslint . --ext .ts", 22 | "clean": "ets clean" 23 | }, 24 | "dependencies": { 25 | "egg": "^2.6.1", 26 | "egg-scripts": "^2.6.0", 27 | "swagger-egg": "file:../../" 28 | }, 29 | "devDependencies": { 30 | "@types/mocha": "^2.2.40", 31 | "@types/node": "^7.0.12", 32 | "@types/supertest": "^2.0.0", 33 | "autod": "^3.0.1", 34 | "autod-egg": "^1.1.0", 35 | "egg-ci": "^1.8.0", 36 | "egg-bin": "^4.11.0", 37 | "egg-mock": "^3.16.0", 38 | "tslib": "^1.9.0", 39 | "eslint": "^6.7.2", 40 | "eslint-config-egg": "^8.0.0", 41 | "typescript": "^3.0.0" 42 | }, 43 | "engines": { 44 | "node": ">=8.9.0" 45 | }, 46 | "ci": { 47 | "version": "8" 48 | }, 49 | "repository": { 50 | "type": "git", 51 | "url": "" 52 | }, 53 | "eslintIgnore": [ 54 | "coverage" 55 | ], 56 | "author": "jsonma", 57 | "license": "MIT" 58 | } 59 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/test/app/controller/home.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import { app } from 'egg-mock/bootstrap'; 3 | 4 | describe('test/app/controller/home.test.ts', () => { 5 | it('should GET /', async () => { 6 | const result = await app.httpRequest().get('/').expect(200); 7 | assert(result.text === 'hi, egg'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/test/app/service/Test.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import { Context } from 'egg'; 3 | import { app } from 'egg-mock/bootstrap'; 4 | 5 | describe('test/app/service/Test.test.js', () => { 6 | let ctx: Context; 7 | 8 | before(async () => { 9 | ctx = app.mockContext(); 10 | }); 11 | 12 | it('sayHi', async () => { 13 | const result = await ctx.service.test.sayHi('egg'); 14 | assert(result === 'hi, egg'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "target": "es2017", 5 | "module": "commonjs", 6 | "strict": true, 7 | "noImplicitAny": false, 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "charset": "utf8", 11 | "allowJs": false, 12 | "pretty": true, 13 | "noEmitOnError": false, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "allowUnreachableCode": false, 17 | "allowUnusedLabels": false, 18 | "strictPropertyInitialization": false, 19 | "noFallthroughCasesInSwitch": true, 20 | "skipLibCheck": true, 21 | "skipDefaultLibCheck": true, 22 | "inlineSourceMap": true, 23 | "importHelpers": true 24 | }, 25 | "exclude": [ 26 | "app/public", 27 | "app/views", 28 | "node_modules*" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/typings/app/controller/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | import ExportHome from '../../../app/controller/home'; 6 | 7 | declare module 'egg' { 8 | interface IController { 9 | home: ExportHome; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/typings/app/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | export * from 'egg'; 6 | export as namespace Egg; 7 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/typings/app/service/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | type AnyClass = new (...args: any[]) => any; 6 | type AnyFunc = (...args: any[]) => T; 7 | type CanExportFunc = AnyFunc> | AnyFunc>; 8 | type AutoInstanceType : T> = U extends AnyClass ? InstanceType : U; 9 | import ExportTest from '../../../app/service/Test'; 10 | 11 | declare module 'egg' { 12 | interface IService { 13 | test: AutoInstanceType; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/typings/config/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | import { EggAppConfig } from 'egg'; 6 | import ExportConfigDefault from '../../config/config.default'; 7 | type ConfigDefault = ReturnType; 8 | type NewEggAppConfig = ConfigDefault; 9 | declare module 'egg' { 10 | interface EggAppConfig extends NewEggAppConfig { } 11 | } -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/typings/config/plugin.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper@1.30.2 2 | // Do not modify this file!!!!!!!!! 3 | 4 | import 'egg'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import 'swagger-egg'; 18 | import { EggPluginItem } from 'egg'; 19 | declare module 'egg' { 20 | interface EggPlugin { 21 | onerror?: EggPluginItem; 22 | session?: EggPluginItem; 23 | i18n?: EggPluginItem; 24 | watcher?: EggPluginItem; 25 | multipart?: EggPluginItem; 26 | security?: EggPluginItem; 27 | development?: EggPluginItem; 28 | logrotator?: EggPluginItem; 29 | schedule?: EggPluginItem; 30 | static?: EggPluginItem; 31 | jsonp?: EggPluginItem; 32 | view?: EggPluginItem; 33 | swaggerEgg?: EggPluginItem; 34 | } 35 | } -------------------------------------------------------------------------------- /example/egg-swagger-ts-schema-example/typings/index.d.ts: -------------------------------------------------------------------------------- 1 | import 'egg'; 2 | 3 | declare module 'egg' { 4 | 5 | } -------------------------------------------------------------------------------- /example/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.", 5 | "version": "1.0.5", 6 | "title": "Swagger Petstore", 7 | "termsOfService": "http://swagger.io/terms/", 8 | "contact": { 9 | "email": "apiteam@swagger.io" 10 | }, 11 | "license": { 12 | "name": "Apache 2.0", 13 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html" 14 | } 15 | }, 16 | "host": "petstore.swagger.io", 17 | "basePath": "/v2", 18 | "tags": [ 19 | { 20 | "name": "pet", 21 | "description": "Everything about your Pets", 22 | "externalDocs": { 23 | "description": "Find out more", 24 | "url": "http://swagger.io" 25 | } 26 | }, 27 | { 28 | "name": "store", 29 | "description": "Access to Petstore orders" 30 | }, 31 | { 32 | "name": "user", 33 | "description": "Operations about user", 34 | "externalDocs": { 35 | "description": "Find out more about our store", 36 | "url": "http://swagger.io" 37 | } 38 | } 39 | ], 40 | "schemes": [ 41 | "https", 42 | "http" 43 | ], 44 | "paths": { 45 | "/pet/{petId}/uploadImage": { 46 | "post": { 47 | "tags": [ 48 | "pet" 49 | ], 50 | "summary": "uploads an image", 51 | "description": "", 52 | "operationId": "uploadFile", 53 | "consumes": [ 54 | "multipart/form-data" 55 | ], 56 | "produces": [ 57 | "application/json" 58 | ], 59 | "parameters": [ 60 | { 61 | "name": "petId", 62 | "in": "path", 63 | "description": "ID of pet to update", 64 | "required": true, 65 | "type": "integer", 66 | "format": "int64" 67 | }, 68 | { 69 | "name": "additionalMetadata", 70 | "in": "formData", 71 | "description": "Additional data to pass to server", 72 | "required": false, 73 | "type": "string" 74 | }, 75 | { 76 | "name": "file", 77 | "in": "formData", 78 | "description": "file to upload", 79 | "required": false, 80 | "type": "file" 81 | } 82 | ], 83 | "responses": { 84 | "200": { 85 | "description": "successful operation", 86 | "schema": { 87 | "$ref": "#/definitions/ApiResponse" 88 | } 89 | } 90 | }, 91 | "security": [ 92 | { 93 | "petstore_auth": [ 94 | "write:pets", 95 | "read:pets" 96 | ] 97 | } 98 | ] 99 | } 100 | }, 101 | "/pet": { 102 | "post": { 103 | "tags": [ 104 | "pet" 105 | ], 106 | "summary": "Add a new pet to the store", 107 | "description": "", 108 | "operationId": "addPet", 109 | "consumes": [ 110 | "application/json", 111 | "application/xml" 112 | ], 113 | "produces": [ 114 | "application/json", 115 | "application/xml" 116 | ], 117 | "parameters": [ 118 | { 119 | "in": "body", 120 | "name": "body", 121 | "description": "Pet object that needs to be added to the store", 122 | "required": true, 123 | "schema": { 124 | "$ref": "#/definitions/Pet" 125 | } 126 | } 127 | ], 128 | "responses": { 129 | "405": { 130 | "description": "Invalid input" 131 | } 132 | }, 133 | "security": [ 134 | { 135 | "petstore_auth": [ 136 | "write:pets", 137 | "read:pets" 138 | ] 139 | } 140 | ] 141 | }, 142 | "put": { 143 | "tags": [ 144 | "pet" 145 | ], 146 | "summary": "Update an existing pet", 147 | "description": "", 148 | "operationId": "updatePet", 149 | "consumes": [ 150 | "application/json", 151 | "application/xml" 152 | ], 153 | "produces": [ 154 | "application/json", 155 | "application/xml" 156 | ], 157 | "parameters": [ 158 | { 159 | "in": "body", 160 | "name": "body", 161 | "description": "Pet object that needs to be added to the store", 162 | "required": true, 163 | "schema": { 164 | "$ref": "#/definitions/Pet" 165 | } 166 | } 167 | ], 168 | "responses": { 169 | "400": { 170 | "description": "Invalid ID supplied" 171 | }, 172 | "404": { 173 | "description": "Pet not found" 174 | }, 175 | "405": { 176 | "description": "Validation exception" 177 | } 178 | }, 179 | "security": [ 180 | { 181 | "petstore_auth": [ 182 | "write:pets", 183 | "read:pets" 184 | ] 185 | } 186 | ] 187 | } 188 | }, 189 | "/pet/findByStatus": { 190 | "get": { 191 | "tags": [ 192 | "pet" 193 | ], 194 | "summary": "Finds Pets by status", 195 | "description": "Multiple status values can be provided with comma separated strings", 196 | "operationId": "findPetsByStatus", 197 | "produces": [ 198 | "application/json", 199 | "application/xml" 200 | ], 201 | "parameters": [ 202 | { 203 | "name": "status", 204 | "in": "query", 205 | "description": "Status values that need to be considered for filter", 206 | "required": true, 207 | "type": "array", 208 | "items": { 209 | "type": "string", 210 | "enum": [ 211 | "available", 212 | "pending", 213 | "sold" 214 | ], 215 | "default": "available" 216 | }, 217 | "collectionFormat": "multi" 218 | } 219 | ], 220 | "responses": { 221 | "200": { 222 | "description": "successful operation", 223 | "schema": { 224 | "type": "array", 225 | "items": { 226 | "$ref": "#/definitions/Pet" 227 | } 228 | } 229 | }, 230 | "400": { 231 | "description": "Invalid status value" 232 | } 233 | }, 234 | "security": [ 235 | { 236 | "petstore_auth": [ 237 | "write:pets", 238 | "read:pets" 239 | ] 240 | } 241 | ] 242 | } 243 | }, 244 | "/pet/findByTags": { 245 | "get": { 246 | "tags": [ 247 | "pet" 248 | ], 249 | "summary": "Finds Pets by tags", 250 | "description": "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", 251 | "operationId": "findPetsByTags", 252 | "produces": [ 253 | "application/json", 254 | "application/xml" 255 | ], 256 | "parameters": [ 257 | { 258 | "name": "tags", 259 | "in": "query", 260 | "description": "Tags to filter by", 261 | "required": true, 262 | "type": "array", 263 | "items": { 264 | "type": "string" 265 | }, 266 | "collectionFormat": "multi" 267 | } 268 | ], 269 | "responses": { 270 | "200": { 271 | "description": "successful operation", 272 | "schema": { 273 | "type": "array", 274 | "items": { 275 | "$ref": "#/definitions/Pet" 276 | } 277 | } 278 | }, 279 | "400": { 280 | "description": "Invalid tag value" 281 | } 282 | }, 283 | "security": [ 284 | { 285 | "petstore_auth": [ 286 | "write:pets", 287 | "read:pets" 288 | ] 289 | } 290 | ], 291 | "deprecated": true 292 | } 293 | }, 294 | "/pet/{petId}": { 295 | "get": { 296 | "tags": [ 297 | "pet" 298 | ], 299 | "summary": "Find pet by ID", 300 | "description": "Returns a single pet", 301 | "operationId": "getPetById", 302 | "produces": [ 303 | "application/json", 304 | "application/xml" 305 | ], 306 | "parameters": [ 307 | { 308 | "name": "petId", 309 | "in": "path", 310 | "description": "ID of pet to return", 311 | "required": true, 312 | "type": "integer", 313 | "format": "int64" 314 | } 315 | ], 316 | "responses": { 317 | "200": { 318 | "description": "successful operation", 319 | "schema": { 320 | "$ref": "#/definitions/Pet" 321 | } 322 | }, 323 | "400": { 324 | "description": "Invalid ID supplied" 325 | }, 326 | "404": { 327 | "description": "Pet not found" 328 | } 329 | }, 330 | "security": [ 331 | { 332 | "api_key": [] 333 | } 334 | ] 335 | }, 336 | "post": { 337 | "tags": [ 338 | "pet" 339 | ], 340 | "summary": "Updates a pet in the store with form data", 341 | "description": "", 342 | "operationId": "updatePetWithForm", 343 | "consumes": [ 344 | "application/x-www-form-urlencoded" 345 | ], 346 | "produces": [ 347 | "application/json", 348 | "application/xml" 349 | ], 350 | "parameters": [ 351 | { 352 | "name": "petId", 353 | "in": "path", 354 | "description": "ID of pet that needs to be updated", 355 | "required": true, 356 | "type": "integer", 357 | "format": "int64" 358 | }, 359 | { 360 | "name": "name", 361 | "in": "formData", 362 | "description": "Updated name of the pet", 363 | "required": false, 364 | "type": "string" 365 | }, 366 | { 367 | "name": "status", 368 | "in": "formData", 369 | "description": "Updated status of the pet", 370 | "required": false, 371 | "type": "string" 372 | } 373 | ], 374 | "responses": { 375 | "405": { 376 | "description": "Invalid input" 377 | } 378 | }, 379 | "security": [ 380 | { 381 | "petstore_auth": [ 382 | "write:pets", 383 | "read:pets" 384 | ] 385 | } 386 | ] 387 | }, 388 | "delete": { 389 | "tags": [ 390 | "pet" 391 | ], 392 | "summary": "Deletes a pet", 393 | "description": "", 394 | "operationId": "deletePet", 395 | "produces": [ 396 | "application/json", 397 | "application/xml" 398 | ], 399 | "parameters": [ 400 | { 401 | "name": "api_key", 402 | "in": "header", 403 | "required": false, 404 | "type": "string" 405 | }, 406 | { 407 | "name": "petId", 408 | "in": "path", 409 | "description": "Pet id to delete", 410 | "required": true, 411 | "type": "integer", 412 | "format": "int64" 413 | } 414 | ], 415 | "responses": { 416 | "400": { 417 | "description": "Invalid ID supplied" 418 | }, 419 | "404": { 420 | "description": "Pet not found" 421 | } 422 | }, 423 | "security": [ 424 | { 425 | "petstore_auth": [ 426 | "write:pets", 427 | "read:pets" 428 | ] 429 | } 430 | ] 431 | } 432 | }, 433 | "/store/inventory": { 434 | "get": { 435 | "tags": [ 436 | "store" 437 | ], 438 | "summary": "Returns pet inventories by status", 439 | "description": "Returns a map of status codes to quantities", 440 | "operationId": "getInventory", 441 | "produces": [ 442 | "application/json" 443 | ], 444 | "parameters": [], 445 | "responses": { 446 | "200": { 447 | "description": "successful operation", 448 | "schema": { 449 | "type": "object", 450 | "additionalProperties": { 451 | "type": "integer", 452 | "format": "int32" 453 | } 454 | } 455 | } 456 | }, 457 | "security": [ 458 | { 459 | "api_key": [] 460 | } 461 | ] 462 | } 463 | }, 464 | "/store/order": { 465 | "post": { 466 | "tags": [ 467 | "store" 468 | ], 469 | "summary": "Place an order for a pet", 470 | "description": "", 471 | "operationId": "placeOrder", 472 | "consumes": [ 473 | "application/json" 474 | ], 475 | "produces": [ 476 | "application/json", 477 | "application/xml" 478 | ], 479 | "parameters": [ 480 | { 481 | "in": "body", 482 | "name": "body", 483 | "description": "order placed for purchasing the pet", 484 | "required": true, 485 | "schema": { 486 | "$ref": "#/definitions/Order" 487 | } 488 | } 489 | ], 490 | "responses": { 491 | "200": { 492 | "description": "successful operation", 493 | "schema": { 494 | "$ref": "#/definitions/Order" 495 | } 496 | }, 497 | "400": { 498 | "description": "Invalid Order" 499 | } 500 | } 501 | } 502 | }, 503 | "/store/order/{orderId}": { 504 | "get": { 505 | "tags": [ 506 | "store" 507 | ], 508 | "summary": "Find purchase order by ID", 509 | "description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions", 510 | "operationId": "getOrderById", 511 | "produces": [ 512 | "application/json", 513 | "application/xml" 514 | ], 515 | "parameters": [ 516 | { 517 | "name": "orderId", 518 | "in": "path", 519 | "description": "ID of pet that needs to be fetched", 520 | "required": true, 521 | "type": "integer", 522 | "maximum": 10, 523 | "minimum": 1, 524 | "format": "int64" 525 | } 526 | ], 527 | "responses": { 528 | "200": { 529 | "description": "successful operation", 530 | "schema": { 531 | "$ref": "#/definitions/Order" 532 | } 533 | }, 534 | "400": { 535 | "description": "Invalid ID supplied" 536 | }, 537 | "404": { 538 | "description": "Order not found" 539 | } 540 | } 541 | }, 542 | "delete": { 543 | "tags": [ 544 | "store" 545 | ], 546 | "summary": "Delete purchase order by ID", 547 | "description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors", 548 | "operationId": "deleteOrder", 549 | "produces": [ 550 | "application/json", 551 | "application/xml" 552 | ], 553 | "parameters": [ 554 | { 555 | "name": "orderId", 556 | "in": "path", 557 | "description": "ID of the order that needs to be deleted", 558 | "required": true, 559 | "type": "integer", 560 | "minimum": 1, 561 | "format": "int64" 562 | } 563 | ], 564 | "responses": { 565 | "400": { 566 | "description": "Invalid ID supplied" 567 | }, 568 | "404": { 569 | "description": "Order not found" 570 | } 571 | } 572 | } 573 | }, 574 | "/user/createWithList": { 575 | "post": { 576 | "tags": [ 577 | "user" 578 | ], 579 | "summary": "Creates list of users with given input array", 580 | "description": "", 581 | "operationId": "createUsersWithListInput", 582 | "consumes": [ 583 | "application/json" 584 | ], 585 | "produces": [ 586 | "application/json", 587 | "application/xml" 588 | ], 589 | "parameters": [ 590 | { 591 | "in": "body", 592 | "name": "body", 593 | "description": "List of user object", 594 | "required": true, 595 | "schema": { 596 | "type": "array", 597 | "items": { 598 | "$ref": "#/definitions/User" 599 | } 600 | } 601 | } 602 | ], 603 | "responses": { 604 | "default": { 605 | "description": "successful operation" 606 | } 607 | } 608 | } 609 | }, 610 | "/user/{username}": { 611 | "get": { 612 | "tags": [ 613 | "user" 614 | ], 615 | "summary": "Get user by user name", 616 | "description": "", 617 | "operationId": "getUserByName", 618 | "produces": [ 619 | "application/json", 620 | "application/xml" 621 | ], 622 | "parameters": [ 623 | { 624 | "name": "username", 625 | "in": "path", 626 | "description": "The name that needs to be fetched. Use user1 for testing. ", 627 | "required": true, 628 | "type": "string" 629 | } 630 | ], 631 | "responses": { 632 | "200": { 633 | "description": "successful operation", 634 | "schema": { 635 | "$ref": "#/definitions/User" 636 | } 637 | }, 638 | "400": { 639 | "description": "Invalid username supplied" 640 | }, 641 | "404": { 642 | "description": "User not found" 643 | } 644 | } 645 | }, 646 | "put": { 647 | "tags": [ 648 | "user" 649 | ], 650 | "summary": "Updated user", 651 | "description": "This can only be done by the logged in user.", 652 | "operationId": "updateUser", 653 | "consumes": [ 654 | "application/json" 655 | ], 656 | "produces": [ 657 | "application/json", 658 | "application/xml" 659 | ], 660 | "parameters": [ 661 | { 662 | "name": "username", 663 | "in": "path", 664 | "description": "name that need to be updated", 665 | "required": true, 666 | "type": "string" 667 | }, 668 | { 669 | "in": "body", 670 | "name": "body", 671 | "description": "Updated user object", 672 | "required": true, 673 | "schema": { 674 | "$ref": "#/definitions/User" 675 | } 676 | } 677 | ], 678 | "responses": { 679 | "400": { 680 | "description": "Invalid user supplied" 681 | }, 682 | "404": { 683 | "description": "User not found" 684 | } 685 | } 686 | }, 687 | "delete": { 688 | "tags": [ 689 | "user" 690 | ], 691 | "summary": "Delete user", 692 | "description": "This can only be done by the logged in user.", 693 | "operationId": "deleteUser", 694 | "produces": [ 695 | "application/json", 696 | "application/xml" 697 | ], 698 | "parameters": [ 699 | { 700 | "name": "username", 701 | "in": "path", 702 | "description": "The name that needs to be deleted", 703 | "required": true, 704 | "type": "string" 705 | } 706 | ], 707 | "responses": { 708 | "400": { 709 | "description": "Invalid username supplied" 710 | }, 711 | "404": { 712 | "description": "User not found" 713 | } 714 | } 715 | } 716 | }, 717 | "/user/login": { 718 | "get": { 719 | "tags": [ 720 | "user" 721 | ], 722 | "summary": "Logs user into the system", 723 | "description": "", 724 | "operationId": "loginUser", 725 | "produces": [ 726 | "application/json", 727 | "application/xml" 728 | ], 729 | "parameters": [ 730 | { 731 | "name": "username", 732 | "in": "query", 733 | "description": "The user name for login", 734 | "required": true, 735 | "type": "string" 736 | }, 737 | { 738 | "name": "password", 739 | "in": "query", 740 | "description": "The password for login in clear text", 741 | "required": true, 742 | "type": "string" 743 | } 744 | ], 745 | "responses": { 746 | "200": { 747 | "description": "successful operation", 748 | "headers": { 749 | "X-Expires-After": { 750 | "type": "string", 751 | "format": "date-time", 752 | "description": "date in UTC when token expires" 753 | }, 754 | "X-Rate-Limit": { 755 | "type": "integer", 756 | "format": "int32", 757 | "description": "calls per hour allowed by the user" 758 | } 759 | }, 760 | "schema": { 761 | "type": "string" 762 | } 763 | }, 764 | "400": { 765 | "description": "Invalid username/password supplied" 766 | } 767 | } 768 | } 769 | }, 770 | "/user/logout": { 771 | "get": { 772 | "tags": [ 773 | "user" 774 | ], 775 | "summary": "Logs out current logged in user session", 776 | "description": "", 777 | "operationId": "logoutUser", 778 | "produces": [ 779 | "application/json", 780 | "application/xml" 781 | ], 782 | "parameters": [], 783 | "responses": { 784 | "default": { 785 | "description": "successful operation" 786 | } 787 | } 788 | } 789 | }, 790 | "/user/createWithArray": { 791 | "post": { 792 | "tags": [ 793 | "user" 794 | ], 795 | "summary": "Creates list of users with given input array", 796 | "description": "", 797 | "operationId": "createUsersWithArrayInput", 798 | "consumes": [ 799 | "application/json" 800 | ], 801 | "produces": [ 802 | "application/json", 803 | "application/xml" 804 | ], 805 | "parameters": [ 806 | { 807 | "in": "body", 808 | "name": "body", 809 | "description": "List of user object", 810 | "required": true, 811 | "schema": { 812 | "type": "array", 813 | "items": { 814 | "$ref": "#/definitions/User" 815 | } 816 | } 817 | } 818 | ], 819 | "responses": { 820 | "default": { 821 | "description": "successful operation" 822 | } 823 | } 824 | } 825 | }, 826 | "/user": { 827 | "post": { 828 | "tags": [ 829 | "user" 830 | ], 831 | "summary": "Create user", 832 | "description": "This can only be done by the logged in user.", 833 | "operationId": "createUser", 834 | "consumes": [ 835 | "application/json" 836 | ], 837 | "produces": [ 838 | "application/json", 839 | "application/xml" 840 | ], 841 | "parameters": [ 842 | { 843 | "in": "body", 844 | "name": "body", 845 | "description": "Created user object", 846 | "required": true, 847 | "schema": { 848 | "$ref": "#/definitions/User" 849 | } 850 | } 851 | ], 852 | "responses": { 853 | "default": { 854 | "description": "successful operation" 855 | } 856 | } 857 | } 858 | } 859 | }, 860 | "securityDefinitions": { 861 | "api_key": { 862 | "type": "apiKey", 863 | "name": "api_key", 864 | "in": "header" 865 | }, 866 | "petstore_auth": { 867 | "type": "oauth2", 868 | "authorizationUrl": "https://petstore.swagger.io/oauth/authorize", 869 | "flow": "implicit", 870 | "scopes": { 871 | "read:pets": "read your pets", 872 | "write:pets": "modify pets in your account" 873 | } 874 | } 875 | }, 876 | "definitions": { 877 | "ApiResponse": { 878 | "type": "object", 879 | "properties": { 880 | "code": { 881 | "type": "integer", 882 | "format": "int32" 883 | }, 884 | "type": { 885 | "type": "string" 886 | }, 887 | "message": { 888 | "type": "string" 889 | } 890 | } 891 | }, 892 | "Category": { 893 | "type": "object", 894 | "properties": { 895 | "id": { 896 | "type": "integer", 897 | "format": "int64" 898 | }, 899 | "name": { 900 | "type": "string" 901 | } 902 | }, 903 | "xml": { 904 | "name": "Category" 905 | } 906 | }, 907 | "Pet": { 908 | "type": "object", 909 | "required": [ 910 | "name", 911 | "photoUrls" 912 | ], 913 | "properties": { 914 | "id": { 915 | "type": "integer", 916 | "format": "int64" 917 | }, 918 | "category": { 919 | "$ref": "#/definitions/Category" 920 | }, 921 | "name": { 922 | "type": "string", 923 | "example": "doggie" 924 | }, 925 | "photoUrls": { 926 | "type": "array", 927 | "xml": { 928 | "wrapped": true 929 | }, 930 | "items": { 931 | "type": "string", 932 | "xml": { 933 | "name": "photoUrl" 934 | } 935 | } 936 | }, 937 | "tags": { 938 | "type": "array", 939 | "xml": { 940 | "wrapped": true 941 | }, 942 | "items": { 943 | "xml": { 944 | "name": "tag" 945 | }, 946 | "$ref": "#/definitions/Tag" 947 | } 948 | }, 949 | "status": { 950 | "type": "string", 951 | "description": "pet status in the store", 952 | "enum": [ 953 | "available", 954 | "pending", 955 | "sold" 956 | ] 957 | } 958 | }, 959 | "xml": { 960 | "name": "Pet" 961 | } 962 | }, 963 | "Tag": { 964 | "type": "object", 965 | "properties": { 966 | "id": { 967 | "type": "integer", 968 | "format": "int64" 969 | }, 970 | "name": { 971 | "type": "string" 972 | } 973 | }, 974 | "xml": { 975 | "name": "Tag" 976 | } 977 | }, 978 | "Order": { 979 | "type": "object", 980 | "properties": { 981 | "id": { 982 | "type": "integer", 983 | "format": "int64" 984 | }, 985 | "petId": { 986 | "type": "integer", 987 | "format": "int64" 988 | }, 989 | "quantity": { 990 | "type": "integer", 991 | "format": "int32" 992 | }, 993 | "shipDate": { 994 | "type": "string", 995 | "format": "date-time" 996 | }, 997 | "status": { 998 | "type": "string", 999 | "description": "Order Status", 1000 | "enum": [ 1001 | "placed", 1002 | "approved", 1003 | "delivered" 1004 | ] 1005 | }, 1006 | "complete": { 1007 | "type": "boolean" 1008 | } 1009 | }, 1010 | "xml": { 1011 | "name": "Order" 1012 | } 1013 | }, 1014 | "User": { 1015 | "type": "object", 1016 | "properties": { 1017 | "id": { 1018 | "type": "integer", 1019 | "format": "int64" 1020 | }, 1021 | "username": { 1022 | "type": "string" 1023 | }, 1024 | "firstName": { 1025 | "type": "string" 1026 | }, 1027 | "lastName": { 1028 | "type": "string" 1029 | }, 1030 | "email": { 1031 | "type": "string" 1032 | }, 1033 | "password": { 1034 | "type": "string" 1035 | }, 1036 | "phone": { 1037 | "type": "string" 1038 | }, 1039 | "userStatus": { 1040 | "type": "integer", 1041 | "format": "int32", 1042 | "description": "User Status" 1043 | } 1044 | }, 1045 | "xml": { 1046 | "name": "User" 1047 | } 1048 | } 1049 | }, 1050 | "externalDocs": { 1051 | "description": "Find out more about Swagger", 1052 | "url": "http://swagger.io" 1053 | } 1054 | } -------------------------------------------------------------------------------- /lib/comment/comment_loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const assert = require('assert'); 5 | const doctrine = require('doctrine'); 6 | const {loadFile} = require('../file_loader'); 7 | 8 | /** 9 | * Get comment blocks from target file 10 | * 11 | * @param {string} filePath - file path 12 | * @return {array} comment blocks 13 | */ 14 | function getCommentBlocks(filePath) { 15 | const fileExtension = path.extname(filePath); 16 | assert(['.js', '.ts'].includes(fileExtension), `Unkonw file extension ${fileExtension}`); 17 | const commentReg = /\/\*\*\r?\n([\s\S]*?)\*\//gim; 18 | const fileString = loadFile(filePath); 19 | return fileString.match(commentReg) || []; 20 | } 21 | 22 | /** 23 | * Get comment info from comment block 24 | * 25 | * @param {string} commentBlock - comment block string 26 | * @return {object} - jsdoc comment 27 | */ 28 | function getComment(commentBlock) { 29 | return doctrine.parse(commentBlock, {unwrap: true}); 30 | } 31 | 32 | module.exports = (filePath) => { 33 | const blocks = getCommentBlocks(filePath); 34 | // Ignore comments with deprecated tag 35 | const filterdBlock = blocks.filter((block) => block.includes('#swagger-api') && !block.includes('@deprecated')); 36 | return filterdBlock.map((block) => getComment(block)); 37 | }; 38 | -------------------------------------------------------------------------------- /lib/comment/comment_parser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | 5 | /** 6 | * Parameter comment parser 7 | * 8 | * @param {string} parameterString - Parameter string 9 | * @example id path parameterSchema true - desc 10 | * @return {object} parameter object 11 | * @example 12 | * ```javascript 13 | * { 14 | * "name": "id", 15 | * "in": "path", 16 | * "description": "id parameter in path", 17 | * "required": true, 18 | * "schema": { 19 | * "type": "integer", 20 | * "format": "int64" 21 | * } 22 | * } 23 | * ``` 24 | */ 25 | function parameterParser(parameterString) { 26 | const parameterObj = {}; 27 | // Description is optional 28 | const splitedParams = parameterString.match(/\s*-\s+[\s\S]+/g); 29 | const description = splitedParams.pop().replace('-', '').trim() || ''; 30 | // Match string which begin with one or more whitespace 31 | const result = parameterString.replace(/\s*-\s+[\s\S]+/g, '').match(/\s+(\S)+/g); 32 | assert(result.length === 4, `Parameter comment format error: ${parameterString}`); 33 | const name = result.shift().trim(); 34 | // Deal with key word "in" 35 | const _in = result.shift().trim(); 36 | assert(['query', 'header', 'path', 'formData', 'body'].includes(_in), `Unknown parameter field in: ${_in}`); 37 | parameterObj.in = _in; 38 | // Deal with key word "required" 39 | const schemaArray = result.shift().trim().split('.'); 40 | let required = result.shift().trim(); 41 | assert(['true', 'false'].includes(required), `parameter's required field should be boolean type, got: ${_in}`); 42 | required = _in === 'path' ? true : required === 'true'; // force set required to true when path is 'in' 43 | return Object.assign( 44 | { 45 | name, 46 | required, 47 | description, 48 | schemaArray, 49 | }, 50 | parameterObj 51 | ); 52 | } 53 | 54 | /** 55 | * Response comment parser 56 | * 57 | * @param {string} responseString - Response string 58 | * @example 200 responseSchema - desc 59 | * @return {object} Response object 60 | * @example 61 | * ```javascript 62 | * { 63 | * "status": "200", 64 | * "description": "Response description", 65 | * "schema": "responseSchema" 66 | * } 67 | * ``` 68 | */ 69 | function responnseParser(responseString) { 70 | // Description is optional 71 | const splitedParams = responseString.match(/\s*-\s+[\s\S]+/g); 72 | const description = splitedParams.pop().replace('-', '').trim() || ''; 73 | // Match string which begin with one or more whitespace 74 | const result = responseString.replace(/\s*-\s+[\s\S]+/g, '').match(/\s+(\S)+/g); 75 | assert(result.length === 2, `Response comment format error: ${responseString}`); 76 | const status = result.shift().trim(); 77 | const schemaArray = result.shift().trim().split('.'); 78 | return { 79 | status, 80 | description, 81 | schemaArray, 82 | }; 83 | } 84 | 85 | module.exports = { 86 | parameterParser, 87 | responnseParser, 88 | }; 89 | -------------------------------------------------------------------------------- /lib/file_loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const globby = require('globby'); 5 | 6 | module.exports = { 7 | globbyFile(directory) { 8 | const files = '**/*.(js|ts)'; 9 | return globby.sync(files, {cwd: directory}); 10 | }, 11 | loadFile(filepath, module = false) { 12 | try { 13 | if (module) { 14 | // require js module 15 | const obj = require(filepath); 16 | if (!obj) return obj; 17 | // it's es module 18 | if (obj.__esModule) return 'default' in obj ? obj.default : obj; 19 | return obj; 20 | } 21 | return fs.readFileSync(filepath).toString(); 22 | } catch (err) { 23 | err.message = `[egg-core] load file: ${filepath}, error: ${err.message}`; 24 | throw err; 25 | } 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/router_loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const {loadFile} = require('./file_loader'); 5 | const {detectProjectLanguage} = require('./utils'); 6 | class RouterLoader { 7 | /** RouterLoader Class constructor 8 | * 9 | * @param {object} app - Application 10 | * @param {string} filePath - Router file path 11 | */ 12 | constructor(app, filePath) { 13 | this.prefix = app.router.opts.prefix || ''; 14 | this.filePath = filePath; 15 | this.routerMap = new Map(); 16 | this.routerFileString = loadFile(filePath); 17 | this.config = app.config.swaggerEgg; 18 | this.fileExtend = detectProjectLanguage(app); 19 | } 20 | 21 | /** 22 | * Get router infomation from common router file string 23 | * 24 | * @param {string} fileString - File string 25 | */ 26 | getCommonRouter(fileString) { 27 | const routers = fileString.match(/(head|options|get|put|post|patch|delete|del|redirect)\((\s|\S)*?\)/g); 28 | if (routers) { 29 | routers.forEach((router) => { 30 | const methodResult = router.match(/^(head|options|get|put|post|patch|delete|del|redirect)/g); 31 | const method = methodResult && methodResult[0]; 32 | const actionResult = router.match(/\((\s|\S)*?\)$/g); 33 | const actionStr = actionResult && actionResult[0]; 34 | const actionArray = actionStr.replace(/(\(|\)|\s)/g, '').split(','); 35 | const action = actionArray.pop(); 36 | const stringReg = /\'|`/g; 37 | const pathNameArray = actionArray.filter((item) => { 38 | return stringReg.test(item); 39 | }); 40 | const path = `${this.prefix}${pathNameArray.length ? pathNameArray.pop().replace(/\'|`/g, '') : ''}`; 41 | const name = pathNameArray.length ? pathNameArray.pop().replace(/\'|`/g, '') : null; 42 | this.routerMap.set(action, { 43 | method, 44 | path, 45 | name, 46 | }); 47 | }); 48 | } 49 | } 50 | 51 | /** 52 | * Get router infomation from RESTful style router file string 53 | * 54 | * @param {string} fileString - File string 55 | */ 56 | getRESTfulRouter(fileString) { 57 | const routers = fileString.match(/resources\((.*)\)/g); 58 | if (routers) { 59 | routers.forEach((router) => { 60 | let routerResource = router.replace(/(resources|\s|\(|\)|')/g, ''); 61 | if (routerResource) routerResource = routerResource.split(','); 62 | routerResource.shift(); 63 | const path = `${this.prefix}${routerResource.shift()}`; 64 | const action = routerResource.pop(); 65 | [ 66 | { 67 | action: `${action}.index`, 68 | method: 'get', 69 | path, 70 | }, 71 | { 72 | action: `${action}.new`, 73 | method: 'get', 74 | path: `${path}/new`, 75 | }, 76 | { 77 | action: `${action}.show`, 78 | method: 'get', 79 | path: `${path}/:id`, 80 | }, 81 | { 82 | action: `${action}.edit`, 83 | method: 'get', 84 | path: `${path}/:id/edit`, 85 | }, 86 | { 87 | action: `${action}.create`, 88 | method: 'post', 89 | path, 90 | }, 91 | { 92 | action: `${action}.update`, 93 | method: 'put', 94 | path: `${path}/:id`, 95 | }, 96 | { 97 | action: `${action}.destroy`, 98 | method: 'delete', 99 | path: `${path}/:id`, 100 | }, 101 | ].forEach((item) => { 102 | this.routerMap.set(item.action, { 103 | method: item.method, 104 | path: item.path.replace(/\'|`/g, ''), 105 | }); 106 | }); 107 | }); 108 | } 109 | } 110 | 111 | /** 112 | * Get router infomation from mixin style router file string 113 | * @param {string} routerFileString - Router file string 114 | */ 115 | getMixinRouter(routerFileString) { 116 | this.getRESTfulRouter(routerFileString); 117 | this.getCommonRouter(routerFileString); 118 | } 119 | 120 | /** 121 | * Get router infomation from target file or folder 122 | * 123 | */ 124 | getRouter() { 125 | const dependencies = this.routerFileString.match(/require\((\s|\S)*?\)/g); 126 | if (dependencies) { 127 | dependencies 128 | .map((item) => item.replace(/(require|\(|\)|\s|')/g, '')) 129 | .filter((dependency) => dependency.includes('/router/') || dependency.includes('/routers/')) 130 | .forEach((dependencyPath) => { 131 | const dependencyFileString = loadFile( 132 | path.join(path.dirname(this.filePath), `${dependencyPath}.${this.fileExtend}`) 133 | ); 134 | this.getMixinRouter(dependencyFileString); 135 | }); 136 | } 137 | this.getMixinRouter(this.routerFileString); 138 | } 139 | } 140 | 141 | module.exports = RouterLoader; 142 | -------------------------------------------------------------------------------- /lib/schema_loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const assert = require('assert'); 5 | const path = require('path'); 6 | const {globbyFile, loadFile} = require('./file_loader'); 7 | const utils = require('./utils'); 8 | 9 | /** 10 | * Load schema object from target directory 11 | * 12 | * @param {string} dirPath shcema directory path 13 | * @return {object} - schema object 14 | */ 15 | function schemaLoader(dirPath) { 16 | assert(fs.existsSync(dirPath), `schema directory not exists: ${dirPath}`); 17 | 18 | const schemaFiles = globbyFile(dirPath) || []; 19 | const schemaObj = {}; 20 | schemaFiles.forEach((file) => { 21 | const extname = path.extname(file); 22 | if (extname === '.js' || extname === '.ts') { 23 | const keys = utils.camelCase(file.replace(extname, '')).split('/'); 24 | let value = loadFile(path.join(dirPath, file), true); 25 | const rootKey = keys.shift(); 26 | if (keys.length) { 27 | value = keys.reduce((acc, key) => { 28 | const emptyObj = {}; 29 | if (typeof acc !== 'object') acc = value; 30 | emptyObj[key] = acc; 31 | return emptyObj; 32 | }, value); 33 | } 34 | if (!schemaObj[rootKey]) schemaObj[rootKey] = value; 35 | else Object.assign(schemaObj[rootKey], value); 36 | } 37 | }); 38 | return schemaObj; 39 | } 40 | 41 | module.exports = schemaLoader; 42 | -------------------------------------------------------------------------------- /lib/swagger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const fse = require('fs-extra'); 5 | const assert = require('assert'); 6 | const path = require('path'); 7 | const Router = require('./router_loader'); 8 | const { globbyFile, loadFile } = require('./file_loader'); 9 | const commentLoader = require('./comment/comment_loader'); 10 | const commentParser = require('./comment/comment_parser'); 11 | const schemaLoader = require('./schema_loader'); 12 | const ts2schemaLoader = require('./ts2schema_loader'); 13 | const utils = require('./utils'); 14 | const crypto = require('crypto'); 15 | 16 | class Swagger { 17 | constructor(app, pathToSwaggerUi) { 18 | this.app = app; 19 | this.swaggerUiPath = pathToSwaggerUi; 20 | this.baseDir = app.config.baseDir; 21 | this.config = app.config.swaggerEgg; 22 | this.supportDataType = ['string', 'number', 'integer', 'boolean', 'array', 'file']; 23 | this.fileExtend = utils.detectProjectLanguage(app); 24 | this.build(); 25 | } 26 | 27 | build() { 28 | // Prepare swagger default object 29 | this.swaggerObject = utils.prepareSwaggerObject(this.app, utils.prepareDefaultOptions(this.config)); 30 | 31 | // Load router file 32 | const routerPath = path.join(this.baseDir, `/app/router.${this.fileExtend}`); 33 | 34 | this.router = new Router(this.app, routerPath); 35 | this.router.getRouter(); 36 | 37 | // Load schema file 38 | const schemaPath = path.join(this.baseDir, this.config.schema.path); 39 | const schemaObject = this.config.typescriptJsonSchema 40 | ? ts2schemaLoader(schemaPath, this.baseDir) 41 | : schemaLoader(schemaPath); 42 | 43 | if (schemaObject.definitions) { 44 | this.swaggerObject.definitions = schemaObject.definitions; 45 | } 46 | 47 | // add inner definitions 48 | Object.keys(schemaObject).forEach((key) => { 49 | if (schemaObject[key].definitions) { 50 | this.swaggerObject.definitions = Object.assign( 51 | this.swaggerObject.definitions || {}, 52 | schemaObject[key].definitions 53 | ); 54 | } 55 | }); 56 | 57 | this.schema = schemaObject; 58 | 59 | // add swagger attribute to app instance 60 | this.app.swagger = { 61 | schema: schemaObject, 62 | }; 63 | 64 | // Scanner controller directory 65 | const controllerDirectory = path.join(this.baseDir, '/app/controller'); 66 | const files = globbyFile(controllerDirectory); 67 | for (const file of files) { 68 | const fileName = utils.camelCase(file.replace(/\.(js|ts)$/, '').replace('/', '.')); 69 | const filePath = path.join(this.baseDir, `/app/controller/${file}`); 70 | const comments = commentLoader(filePath); 71 | let functionName = null; 72 | if (!comments.length) continue; 73 | for (const comment of comments) { 74 | if (!comment.tags.length) continue; 75 | const { tags, description: rawDescription } = comment; 76 | const description = rawDescription.replace(/\s{0,}#swagger-api$/g, ''); 77 | let functionIndex = null; 78 | 79 | // Get action from jsdoc function tag 80 | tags.forEach((tag, index) => { 81 | if (tag.title === 'function') { 82 | assert(!functionIndex, `Duplex function tag of ${JSON.stringify(tag)}`); 83 | functionIndex = index; 84 | } 85 | }); 86 | if (functionIndex === null) continue; 87 | const tag = tags.splice(functionIndex, 1); 88 | functionName = tag[0].name; 89 | const action = `controller\.${fileName}\.${functionName}`; 90 | const appPrefixAction = `app.controller\.${fileName}\.${functionName}`; 91 | const operationId = `${fileName}/${functionName}`; 92 | 93 | // Get method and path from routerMap 94 | const routerObject = this.router.routerMap.get(action) || this.router.routerMap.get(appPrefixAction); 95 | if (routerObject) { 96 | let { path, method } = routerObject; 97 | if (!this.swaggerObject.paths[path]) { 98 | this.swaggerObject.paths[path] = {}; 99 | } 100 | this.swaggerObject.paths[path][method] = { 101 | description, 102 | operationId, 103 | parameters: [], 104 | responses: {}, 105 | }; 106 | 107 | // Deal with other swagger tags 108 | for (const tag of tags) { 109 | const { title, description } = tag; 110 | if (title === 'description' && description.length) { 111 | const types = description.match(/#(parameters|responses|consumes|produces|tags)/g); 112 | if (!types) continue; 113 | const type = types.shift(); 114 | const params = description.replace(`#${type}`, ''); 115 | switch (type) { 116 | case '#parameters': 117 | path = this.getParameter(path, method, params); 118 | break; 119 | case '#responses': 120 | this.getResponnseParser(path, method, params); 121 | break; 122 | case '#consumes': 123 | this.getCommonParser(path, method, params, 'consumes'); 124 | break; 125 | case '#produces': 126 | this.getCommonParser(path, method, params, 'produces'); 127 | break; 128 | default: 129 | this.getCommonParser(path, method, params, 'tags'); 130 | break; 131 | } 132 | } else if (title === 'summary' && description.length) { 133 | this.swaggerObject.paths[path][method].summary = description; 134 | } 135 | } 136 | } 137 | } 138 | } 139 | 140 | // Generate swagger.json file 141 | this.generateDocument(); 142 | 143 | // Change swagger-ui-dist's default api url config 144 | const swaggerUiBundlePath = path.join(this.swaggerUiPath, './index.html'); 145 | const prefix = this.app.config.static.prefix || '/public'; 146 | const swaggerUiConfig = this.config.swaggerUI; // swagger ui config 147 | swaggerUiConfig.url = `"${prefix}${/\/$/.test(prefix) ? '' : '/'}swagger/index.json"`; 148 | const bundleFileString = utils.prepareSwaggerUi(loadFile(swaggerUiBundlePath), swaggerUiConfig); 149 | fs.unlinkSync(swaggerUiBundlePath); // delete old file 150 | fs.appendFileSync(swaggerUiBundlePath, bundleFileString); // create new file 151 | } 152 | 153 | /** 154 | * Generate swagger.json file 155 | * 156 | * @memberof Swagger 157 | */ 158 | generateDocument() { 159 | const swaggerDocString = utils.finalize(this.swaggerObject); 160 | const fileMd5Name = crypto.createHash('md5').update(swaggerDocString).digest('hex'); 161 | this.fileMd5Name = fileMd5Name; // set md5 file name 162 | const filePath = path.join(this.app.baseDir, `app/public/swagger/index.json`); 163 | const dirPath = path.join(this.app.baseDir, 'app/public/swagger'); 164 | fse.emptyDirSync(dirPath); // empty target dir 165 | fs.appendFileSync(filePath, swaggerDocString); 166 | } 167 | 168 | getCommonParser(path, method, commomParams, type) { 169 | if (!this.tags && type === 'tags') { 170 | this.tags = this.swaggerObject.tags.map((tagObject) => tagObject.name); 171 | } 172 | const params = commomParams.match(/\s+(\S)+/g) || []; 173 | const trimParams = params.map((param) => { 174 | const trimParams = param.trim(); 175 | if (type === 'tags') { 176 | assert(this.tags.includes(trimParams), `${param} tag is not defined in swagger config`); 177 | } 178 | return trimParams; 179 | }); 180 | this.swaggerObject.paths[path][method][type] = trimParams; 181 | } 182 | 183 | getParameter(path, method, parameterComments) { 184 | let parameter = commentParser.parameterParser(parameterComments); 185 | // replace in parameter in path 186 | if (parameter.in === 'path') { 187 | const originalPath = path; 188 | const originalPathObj = this.swaggerObject.paths[originalPath]; 189 | const reg = new RegExp(`:${parameter.name}`, 'g'); 190 | path = path.replace(reg, `{${parameter.name}}`); 191 | this.swaggerObject.paths[path] = Object.assign({}, this.swaggerObject.paths[path], originalPathObj); 192 | if (originalPath !== path) delete this.swaggerObject.paths[originalPath]; 193 | } 194 | const schema = this.getSchema(parameter.schemaArray); 195 | // delete temporary field 196 | delete parameter.schemaArray; 197 | if (parameter.in === 'body') parameter.schema = schema; 198 | if (parameter.in === 'query') { 199 | const properties = (schema.properties); 200 | parameter=[] 201 | for (const [key, value] of Object.entries(properties)) { 202 | parameter.push({ ...value, name:key,in: 'query', require: schema.required.includes(key) }) 203 | } 204 | } 205 | else Object.assign(parameter, schema); 206 | this.swaggerObject.paths[path][method].parameters.push(...(Array.isArray(parameter)?parameter:[parameter])); 207 | return path; 208 | } 209 | 210 | getResponnseParser(path, method, responseComments) { 211 | const parameter = commentParser.responnseParser(responseComments); 212 | const { status, description, schemaArray } = parameter; 213 | const schema = this.getSchema(schemaArray); 214 | if (schema && schema.$ref) { 215 | schema.$ref = decodeURIComponent(schema.$ref); 216 | } 217 | this.swaggerObject.paths[path][method].responses[status] = { 218 | description, 219 | schema, 220 | }; 221 | } 222 | 223 | getSchema(parameter) { 224 | const type = parameter[0]; 225 | if (this.supportDataType.includes(type)) { 226 | return { 227 | type, 228 | }; 229 | } 230 | const schemaObject = parameter.reduce((acc, item) => { 231 | assert(acc && typeof acc === 'object', `${item} schema is not defined`); 232 | return acc[item] || (acc.definitions && acc.definitions[item]); 233 | }, this); 234 | return schemaObject; 235 | } 236 | } 237 | 238 | module.exports = Swagger; 239 | -------------------------------------------------------------------------------- /lib/ts2schema_loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const assert = require('assert'); 5 | const path = require('path'); 6 | const {globbyFile} = require('./file_loader'); 7 | const TJS = require('typescript-json-schema'); 8 | 9 | /** 10 | * Load ts and transform to schema object from target directory 11 | * 12 | * @param {string} dirPath shcema directory path 13 | * @param {string} baseDir baseDir path 14 | * @return {object} - schema object 15 | */ 16 | function contactLoader(dirPath, baseDir) { 17 | assert(fs.existsSync(dirPath), `shcema directory not exists: ${dirPath}`); 18 | 19 | const files = globbyFile(dirPath) || []; 20 | const schemaObj = {}; 21 | files.forEach((file) => { 22 | const extname = path.extname(file); 23 | if (extname === '.js' || extname === '.ts') { 24 | const program = TJS.programFromConfig(path.join(baseDir, '/tsconfig.json'), [path.join(dirPath, file)]); 25 | const schema = TJS.generateSchema(program, '*', { 26 | required: true, 27 | }); 28 | const keys = file.replace(extname, '').split('/'); 29 | const rootKey = keys.shift(); 30 | let value = schema; 31 | if (keys.length) { 32 | value = keys.reduce((acc, key) => { 33 | const emptyObj = {}; 34 | if (typeof acc !== 'object') acc = value; 35 | emptyObj[key] = acc; 36 | return emptyObj; 37 | }, value); 38 | } 39 | if (!schemaObj[rootKey]) schemaObj[rootKey] = value; 40 | else Object.assign(schemaObj[rootKey], value); 41 | } 42 | }); 43 | return schemaObj; 44 | } 45 | 46 | module.exports = contactLoader; 47 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const swagerParser = require('swagger-parser'); 4 | const YAML = require('yaml'); 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | 8 | /** 9 | * Checks if there is any properties of the input object which are an empty 10 | * 11 | * @param {object} obj - the object to check 12 | * @return {boolean} - result 13 | */ 14 | function noEmptyProperty(obj) { 15 | const keys = Object.keys(obj); 16 | return ( 17 | !!keys.length && 18 | keys 19 | .map((key) => obj[key]) 20 | .every((value) => { 21 | if (typeof value === 'object') { 22 | if (!Object.keys(value).length) return false; 23 | return noEmptyProperty(value); 24 | } 25 | return true; 26 | }) 27 | ); 28 | } 29 | 30 | /** 31 | * Parse the swagger object and remove useless properties if necessary 32 | * 33 | * @param {object} swaggerObject - Swagger object from parsing the api files 34 | * @param {object} ext - Swagger object from parsing the api files 35 | * @return {object} The specification. 36 | */ 37 | function finalize(swaggerObject, ext) { 38 | swagerParser.parse(swaggerObject, (err, api) => { 39 | if (err) throw err; 40 | swaggerObject = api; 41 | }); 42 | if (ext === '.yml' || ext === '.yaml') return YAML.stringify(swaggerObject); 43 | return JSON.stringify(swaggerObject); 44 | } 45 | 46 | /** 47 | * Prepare default options 48 | * @param {object} opts - swagger option 49 | * @return {object} -default options 50 | */ 51 | function prepareDefaultOptions(opts) { 52 | const swagger = opts.swagger; 53 | const info = swagger.info || null; 54 | const host = swagger.host || null; 55 | const schemes = swagger.schemes || null; 56 | const consumes = swagger.consumes || null; 57 | const produces = swagger.produces || null; 58 | const definitions = swagger.definitions || null; 59 | const basePath = swagger.basePath || null; 60 | const securityDefinitions = swagger.securityDefinitions || null; 61 | const security = swagger.security || null; 62 | const tags = swagger.tags || null; 63 | const externalDocs = swagger.externalDocs || null; 64 | const stripBasePath = opts.stripBasePath; 65 | const transform = opts.transform; 66 | const hiddenTag = opts.hiddenTag; 67 | const hideUntagged = opts.hideUntagged; 68 | const extensions = []; 69 | 70 | for (const [key, value] of Object.entries(opts.swagger)) { 71 | if (key.startsWith('x-')) { 72 | extensions.push([key, value]); 73 | } 74 | } 75 | 76 | return { 77 | info, 78 | host, 79 | schemes, 80 | consumes, 81 | produces, 82 | definitions, 83 | basePath, 84 | securityDefinitions, 85 | security, 86 | tags, 87 | externalDocs, 88 | stripBasePath, 89 | transform, 90 | hiddenTag, 91 | extensions, 92 | hideUntagged, 93 | }; 94 | } 95 | 96 | function readPackageJson(app) { 97 | const baseDir = app.config.baseDir; 98 | return JSON.parse(fs.readFileSync(path.join(baseDir, 'package.json'))); 99 | } 100 | 101 | function prepareSwaggerObject(app, opts) { 102 | const pkg = readPackageJson(app); 103 | const swaggerObject = { 104 | swagger: '2.0', 105 | info: { 106 | version: pkg.version || '1.0.0', 107 | title: pkg.name || '', 108 | description: `${pkg.description || ''} API document`, 109 | }, 110 | tags: [], 111 | definitions: {}, 112 | paths: {}, 113 | }; 114 | 115 | if (opts.info) swaggerObject.info = opts.info; 116 | if (opts.host) swaggerObject.host = opts.host; 117 | if (opts.schemes) swaggerObject.schemes = opts.schemes; 118 | if (opts.basePath) swaggerObject.basePath = opts.basePath; 119 | if (opts.consumes) swaggerObject.consumes = opts.consumes; 120 | if (opts.produces) swaggerObject.produces = opts.produces; 121 | if (opts.definitions) swaggerObject.definitions = opts.definitions; 122 | if (opts.securityDefinitions) swaggerObject.securityDefinitions = opts.securityDefinitions; 123 | if (opts.security) swaggerObject.security = opts.security; 124 | if (opts.tags) swaggerObject.tags = opts.tags; 125 | if (opts.externalDocs) swaggerObject.externalDocs = opts.externalDocs; 126 | 127 | for (const [key, value] of opts.extensions) { 128 | // "x-" extension can not be typed 129 | swaggerObject[key] = value; 130 | } 131 | 132 | return swaggerObject; 133 | } 134 | 135 | function prepareSwaggerUi(fileString, config) { 136 | const swaggerUiString = fileString.replace( 137 | / 163 | ` 164 | ); 165 | return swaggerUiString; 166 | } 167 | 168 | function detectProjectLanguage(app) { 169 | try { 170 | const pkgJson = readPackageJson(app); 171 | const baseDir = app.config.baseDir; 172 | if (pkgJson.egg && pkgJson.egg.typescript === true) return 'ts'; 173 | if (fs.statSync(path.join(baseDir, 'tsconfig.json'))) return 'ts'; 174 | return 'js'; 175 | } catch (error) { 176 | return 'js'; 177 | } 178 | } 179 | 180 | // Convert filename to camelCase 181 | function camelCase(fileName) { 182 | const separators = ['-', '_']; 183 | separators.forEach((separator) => { 184 | if (fileName.includes(separator)) { 185 | fileName = fileName.split(separator).reduce((previous, current) => { 186 | return previous + current.slice(0, 1).toUpperCase() + current.substring(1); 187 | }); 188 | } 189 | }); 190 | return fileName; 191 | } 192 | 193 | module.exports = { 194 | noEmptyProperty, 195 | prepareSwaggerUi, 196 | finalize, 197 | prepareDefaultOptions, 198 | prepareSwaggerObject, 199 | detectProjectLanguage, 200 | camelCase, 201 | }; 202 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swagger-egg", 3 | "version": "1.7.6", 4 | "description": "swagger document generator for egg.", 5 | "eggPlugin": { 6 | "name": "swaggerEgg" 7 | }, 8 | "keywords": [ 9 | "egg", 10 | "eggPlugin", 11 | "egg-plugin", 12 | "swagger", 13 | "swagger-doc", 14 | "swagger-api", 15 | "egg-swagger", 16 | "swagger-egg", 17 | "egg-swagger-doc", 18 | "swagger-egg-doc", 19 | "egg-swagger-document", 20 | "swagger-egg-document" 21 | ], 22 | "dependencies": { 23 | "doctrine": "^3.0.0", 24 | "fs-extra": "^10.0.1", 25 | "globby": "^11.0.3", 26 | "is-type-of": "^1.2.1", 27 | "swagger-parser": "^10.0.2", 28 | "swagger-ui-dist": "^3.49.0", 29 | "typescript-json-schema": "^0.53.0", 30 | "yaml": "^1.10.2" 31 | }, 32 | "devDependencies": { 33 | "autod": "^3.0.1", 34 | "autod-egg": "^1.1.0", 35 | "egg": "^2.16.0", 36 | "egg-bin": "^4.11.0", 37 | "egg-ci": "^1.11.0", 38 | "egg-mock": "^3.21.0", 39 | "eslint": "^5.13.0", 40 | "eslint-config-egg": "^7.1.0", 41 | "eslint-config-prettier": "^8.3.0" 42 | }, 43 | "engines": { 44 | "node": ">=8.0.0" 45 | }, 46 | "scripts": { 47 | "test": "npm run lint -- --fix && egg-bin pkgfiles && npm run test-local", 48 | "test-local": "egg-bin test", 49 | "cov": "egg-bin cov", 50 | "lint": "eslint .", 51 | "ci": "egg-bin pkgfiles --check && npm run lint && npm run cov", 52 | "pkgfiles": "egg-bin pkgfiles", 53 | "autod": "autod", 54 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s" 55 | }, 56 | "files": [ 57 | "config", 58 | "app.js", 59 | "lib" 60 | ], 61 | "ci": { 62 | "version": "8, 10" 63 | }, 64 | "repository": { 65 | "type": "git", 66 | "url": "git+https://github.com/JsonMa/swagger-egg.git" 67 | }, 68 | "bugs": { 69 | "url": "https://github.com/JsonMa/swagger-egg/issues" 70 | }, 71 | "homepage": "https://github.com/JsonMa/swagger-egg#readme", 72 | "author": "JsonMa", 73 | "license": "MIT" 74 | } 75 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/controller/admin_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Controller = require('egg').Controller; 4 | 5 | class AdminController extends Controller { 6 | /** 7 | * Index action #swagger-api 8 | * 9 | * @summary This is index action summarys 10 | * @function index 11 | * @memberof AdminController 12 | * @description #tags admin 13 | * @description #produces application/json 14 | * @description #parameters index query number true - index query parameter 15 | * @description #responses 200 schema.adminTest - index response 16 | */ 17 | async index() { 18 | this.ctx.body = 'hi, index action' + this.app.plugins.swaggerEgg.name; 19 | } 20 | 21 | /** 22 | * New action #swagger-api 23 | * 24 | * @summary This is new action summary 25 | * @function new 26 | * @memberof AdminController 27 | * @description #tags admin 28 | * @description #consumes application/x-www-form-urlencoded 29 | * @description #produces application/json 30 | * @description #parameters in body schema.admin true - new body parameter 31 | * @description #responses 200 schema.adminTest - new response 32 | */ 33 | async new() { 34 | this.ctx.body = 'hi, new action' + this.app.plugins.swaggerEgg.name; 35 | } 36 | 37 | /** 38 | * Show action #swagger-api 39 | * 40 | * @summary This is show action summary 41 | * @function show 42 | * @memberof AdminController 43 | * @description #tags admin 44 | * @description #produces application/json 45 | * @description #parameters id path schema.definitions.id true - show path parameter 46 | * @description #responses 200 schema.adminTest - show response 47 | */ 48 | async show() { 49 | this.ctx.body = 'hi, show action' + this.app.plugins.swaggerEgg.name; 50 | } 51 | 52 | /** 53 | * Edit action #swagger-api 54 | * 55 | * @summary This is edit action summary 56 | * @function edit 57 | * @memberof AdminController 58 | * @description #tags admin 59 | * @description #consumes application/x-www-form-urlencoded 60 | * @description #produces application/json 61 | * @description #parameters id path schema.definitions.id true - edit path parameter 62 | * @description #parameters in body schema.admin true - edit body parameter 63 | * @description #responses 200 schema.adminTest - edit response 64 | */ 65 | async edit() { 66 | this.ctx.body = 'hi, edit action ' + this.app.plugins.swaggerEgg.name; 67 | } 68 | 69 | /** 70 | * Create action #swagger-api 71 | * 72 | * @summary This is create action summary 73 | * @function create 74 | * @memberof AdminController 75 | * @description #tags admin 76 | * @description #consumes application/x-www-form-urlencoded 77 | * @description #consumes application/json 78 | * @description #parameters in body schema.admin true - create body parameter 79 | * @description #responses 200 schema.adminTest - create response 80 | */ 81 | async create() { 82 | this.ctx.body = 'hi, create action ' + this.app.plugins.swaggerEgg.name; 83 | } 84 | 85 | /** 86 | * Update action #swagger-api 87 | * 88 | * @summary This is update action summary 89 | * @function update 90 | * @memberof AdminController 91 | * @description #tags admin 92 | * @description #consumes application/x-www-form-urlencoded 93 | * @description #produces application/json 94 | * @description #parameters id path schema.definitions.id true - update path parameter 95 | * @description #parameters id body schema.admin true - update body parameter 96 | * @description #responses 200 schema.adminTest - update response 97 | */ 98 | async update() { 99 | this.ctx.body = 'hi, update action ' + this.app.plugins.swaggerEgg.name; 100 | } 101 | 102 | /** 103 | * Destory action #swagger-api 104 | * 105 | * @summary This is destory action summary 106 | * @function destory 107 | * @memberof AdminController 108 | * @description #tags admin 109 | * @description #consumes application/json 110 | * @description #produces application/json 111 | * @description #parameters id path schema.definitions.id false - destory path parameter 112 | * @description #responses 200 schema.adminTest - destory response 113 | */ 114 | async destory() { 115 | this.ctx.body = 'hi, destory action ' + this.app.plugins.swaggerEgg.name; 116 | } 117 | } 118 | 119 | module.exports = AdminController; 120 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/controller/home-test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Controller = require('egg').Controller; 4 | 5 | class HomeController extends Controller { 6 | 7 | /** 8 | * Index action #swagger-api 9 | * 10 | * @summary This is index action summary 11 | * @function index 12 | * @memberof HomeController 13 | * @description #tags home 14 | * @description #produces application/json 15 | * @description #parameters index query schema.definitions.id true - index query parameter 16 | * @description #responses 200 schema.home - index response 17 | */ 18 | async index() { 19 | this.ctx.body = 'hi, index action' + this.app.plugins.swaggerEgg.name; 20 | } 21 | 22 | /** 23 | * New action #swagger-api 24 | * 25 | * @summary This is new action summary 26 | * @function new 27 | * @memberof HomeController 28 | * @description #tags home 29 | * @description #consumes application/x-www-form-urlencoded 30 | * @description #produces application/json 31 | * @description #parameters in body schema.home true - new body parameter 32 | * @description #responses 200 schema.home - new response 33 | */ 34 | async new() { 35 | this.ctx.body = 'hi, new action' + this.app.plugins.swaggerEgg.name; 36 | } 37 | 38 | /** 39 | * Show action #swagger-api 40 | * 41 | * @summary This is show action summary 42 | * @function show 43 | * @memberof HomeController 44 | * @description #tags home 45 | * @description #produces application/json 46 | * @description #parameters id path schema.definitions.id true - show path parameter 47 | * @description #responses 200 schema.home - show response 48 | */ 49 | async show() { 50 | this.ctx.body = 'hi, show action' + this.app.plugins.swaggerEgg.name; 51 | } 52 | 53 | /** 54 | * Edit action #swagger-api 55 | * 56 | * @summary This is edit action summary 57 | * @function edit 58 | * @memberof HomeController 59 | * @description #tags home 60 | * @description #consumes application/x-www-form-urlencoded 61 | * @description #produces application/json 62 | * @description #parameters id path schema.definitions.id true - edit path parameter 63 | * @description #parameters in body schema.home true - edit body parameter 64 | * @description #responses 200 schema.home - edit response 65 | */ 66 | async edit() { 67 | this.ctx.body = 'hi, edit action ' + this.app.plugins.swaggerEgg.name; 68 | } 69 | 70 | /** 71 | * Create action #swagger-api 72 | * 73 | * @summary This is create action summary 74 | * @function create 75 | * @memberof HomeController 76 | * @description #tags home 77 | * @description #consumes application/x-www-form-urlencoded 78 | * @description #consumes application/json 79 | * @description #parameters in body schema.home true - create body parameter 80 | * @description #responses 200 schema.home - create response 81 | */ 82 | async create() { 83 | this.ctx.body = 'hi, create action ' + this.app.plugins.swaggerEgg.name; 84 | } 85 | 86 | /** 87 | * Update action #swagger-api 88 | * 89 | * @summary This is update action summary 90 | * @function update 91 | * @memberof HomeController 92 | * @description #tags home 93 | * @description #consumes application/x-www-form-urlencoded 94 | * @description #produces application/json 95 | * @description #parameters id path schema.definitions.id true - update path parameter 96 | * @description #parameters id body schema.home true - update body parameter 97 | * @description #responses 200 schema.home - update response 98 | */ 99 | async update() { 100 | this.ctx.body = 'hi, update action ' + this.app.plugins.swaggerEgg.name; 101 | } 102 | 103 | /** 104 | * Destory action #swagger-api 105 | * 106 | * @summary This is destory action summary 107 | * @function destory 108 | * @memberof HomeController 109 | * @description #tags home 110 | * @description #consumes application/json 111 | * @description #produces application/json 112 | * @description #parameters id path schema.definitions.id false - destory path parameter 113 | * @description #responses 200 schema.home - destory response 114 | */ 115 | async destory() { 116 | this.ctx.body = 'hi, destory action ' + this.app.plugins.swaggerEgg.name; 117 | } 118 | } 119 | 120 | module.exports = HomeController; 121 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/controller/posts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This controller file will not generate swagger api automatically 4 | exports.index = async () => {}; 5 | 6 | exports.new = async () => {}; 7 | 8 | exports.create = async () => {}; 9 | 10 | exports.show = async () => {}; 11 | 12 | exports.edit = async () => {}; 13 | 14 | exports.update = async () => {}; 15 | 16 | exports.destroy = async () => {}; 17 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/controller/v1/users.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Controller = require('egg').Controller; 4 | 5 | class UserController extends Controller { 6 | /** 7 | * Index action #swagger-api 8 | * 9 | * @summary This is index action summary 10 | * @function index 11 | * @memberof UserController 12 | * @description #tags user 13 | * @description #produces application/json 14 | * @description #parameters index query schema.definitions.id true - index query parameter 15 | * @description #responses 200 schema.user - index response 16 | */ 17 | async index() { 18 | this.ctx.body = this.ctx.app.swagger.schema.user; 19 | } 20 | 21 | /** 22 | * New action #swagger-api 23 | * 24 | * @summary This is new action summary 25 | * @function new 26 | * @memberof UserController 27 | * @description #tags user 28 | * @description #consumes application/x-www-form-urlencoded 29 | * @description #produces application/json 30 | * @description #parameters in body schema.user true - new body parameter 31 | * @description #responses 200 schema.user - new response 32 | */ 33 | async new() { 34 | this.ctx.body = 'hi, new action' + this.app.plugins.swaggerEgg.name; 35 | } 36 | 37 | /** 38 | * Show action #swagger-api 39 | * 40 | * @summary This is show action summary 41 | * @function show 42 | * @memberof UserController 43 | * @description #tags user 44 | * @description #produces application/json 45 | * @description #parameters id path schema.definitions.id true - show path parameter 46 | * @description #responses 200 schema.user - show response 47 | */ 48 | async show() { 49 | this.ctx.body = 'hi, show action' + this.app.plugins.swaggerEgg.name; 50 | } 51 | 52 | /** 53 | * Edit action #swagger-api 54 | * 55 | * @summary This is edit action summary 56 | * @function edit 57 | * @memberof UserController 58 | * @description #tags user 59 | * @description #consumes application/x-www-form-urlencoded 60 | * @description #produces application/json 61 | * @description #parameters id path schema.definitions.id true - edit path parameter 62 | * @description #parameters in body schema.user true - edit body parameter 63 | * @description #responses 200 schema.user - edit response 64 | */ 65 | async edit() { 66 | this.ctx.body = 'hi, edit action ' + this.app.plugins.swaggerEgg.name; 67 | } 68 | 69 | /** 70 | * Create action #swagger-api 71 | * 72 | * @summary This is create action summary 73 | * @function create 74 | * @memberof UserController 75 | * @description #tags user 76 | * @description #consumes application/x-www-form-urlencoded 77 | * @description #consumes application/json 78 | * @description #parameters in body schema.user true - create body parameter 79 | * @description #responses 200 schema.user - create response 80 | */ 81 | async create() { 82 | this.ctx.body = 'hi, create action ' + this.app.plugins.swaggerEgg.name; 83 | } 84 | 85 | /** 86 | * Update action #swagger-api 87 | * 88 | * @summary This is update action summary 89 | * @function update 90 | * @memberof UserController 91 | * @description #tags user 92 | * @description #consumes application/x-www-form-urlencoded 93 | * @description #produces application/json 94 | * @description #parameters id path schema.definitions.id true - update path parameter 95 | * @description #parameters id body schema.user true - update body parameter 96 | * @description #responses 200 schema.user - update response 97 | */ 98 | async update() { 99 | this.ctx.body = 'hi, update action ' + this.app.plugins.swaggerEgg.name; 100 | } 101 | 102 | /** 103 | * Destory action #swagger-api 104 | * 105 | * @summary This is destory action summary 106 | * @function destory 107 | * @memberof UserController 108 | * @description #tags user 109 | * @description #consumes application/json 110 | * @description #produces application/json 111 | * @description #parameters id path schema.definitions.id false - destory path parameter 112 | * @description #responses 200 schema.user - destory response 113 | */ 114 | async destory() { 115 | this.ctx.body = 'hi, destory action ' + this.app.plugins.swaggerEgg.name; 116 | } 117 | } 118 | 119 | module.exports = UserController; 120 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/public/swagger/0a6fc93a9412ea1ef3375cf695ffcbbd.json: -------------------------------------------------------------------------------- 1 | {"swagger":"2.0","info":{"version":"0.0.1","title":"swagger-egg-test","description":"test description API document"},"tags":[{"name":"admin","description":"Everything about your admin"},{"name":"user","description":"Everything about your user"},{"name":"home","description":"Everything about your home"}],"definitions":{"id":{"type":"string"},"index":{"type":"string"}},"paths":{"/api/v1/admin":{"get":{"description":"Index action","operationId":"adminTest/index","parameters":[{"name":"index","required":true,"description":"index query parameter","in":"query","type":"number"}],"responses":{"200":{"description":"index response","schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"$ref":"schema.definition#/int"},"telephone":{"type":"string"}},"required":["name","telephone","id"],"additionalProperties":false}}},"summary":"This is index action summarys","tags":["admin"],"produces":["application/json"]},"post":{"description":"Create action","operationId":"adminTest/create","parameters":[{"name":"in","required":true,"description":"create body parameter","in":"body"}],"responses":{"200":{"description":"create response","schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"$ref":"schema.definition#/int"},"telephone":{"type":"string"}},"required":["name","telephone","id"],"additionalProperties":false}}},"summary":"This is create action summary","tags":["admin"],"consumes":["application/json"]}},"/api/v1/admin/new":{"get":{"description":"New action","operationId":"adminTest/new","parameters":[{"name":"in","required":true,"description":"new body parameter","in":"body"}],"responses":{"200":{"description":"new response","schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"$ref":"schema.definition#/int"},"telephone":{"type":"string"}},"required":["name","telephone","id"],"additionalProperties":false}}},"summary":"This is new action summary","tags":["admin"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]}},"/api/v1/admin/{id}":{"get":{"description":"Show action","operationId":"adminTest/show","parameters":[{"name":"id","required":true,"description":"show path parameter","in":"path","type":"string"}],"responses":{"200":{"description":"show response","schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"$ref":"schema.definition#/int"},"telephone":{"type":"string"}},"required":["name","telephone","id"],"additionalProperties":false}}},"summary":"This is show action summary","tags":["admin"],"produces":["application/json"]},"put":{"description":"Update action","operationId":"adminTest/update","parameters":[{"name":"id","required":true,"description":"update path parameter","in":"path","type":"string"},{"name":"id","required":true,"description":"update body parameter","in":"body"}],"responses":{"200":{"description":"update response","schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"$ref":"schema.definition#/int"},"telephone":{"type":"string"}},"required":["name","telephone","id"],"additionalProperties":false}}},"summary":"This is update action summary","tags":["admin"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]},"delete":{"description":"Destory action","operationId":"adminTest/destory","parameters":[{"name":"id","required":true,"description":"destory path parameter","in":"path","type":"string"}],"responses":{"200":{"description":"destory response","schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"$ref":"schema.definition#/int"},"telephone":{"type":"string"}},"required":["name","telephone","id"],"additionalProperties":false}}},"summary":"This is destory action summary","tags":["admin"],"consumes":["application/json"],"produces":["application/json"]}},"/api/v1/admin/{id}/edit":{"get":{"description":"Edit action","operationId":"adminTest/edit","parameters":[{"name":"id","required":true,"description":"edit path parameter","in":"path","type":"string"},{"name":"in","required":true,"description":"edit body parameter","in":"body"}],"responses":{"200":{"description":"edit response","schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"$ref":"schema.definition#/int"},"telephone":{"type":"string"}},"required":["name","telephone","id"],"additionalProperties":false}}},"summary":"This is edit action summary","tags":["admin"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]}},"/api/v1/homes":{"get":{"description":"Index action","operationId":"homeTest/index","parameters":[{"name":"index","required":true,"description":"index query parameter","in":"query","type":"string"}],"responses":{"200":{"description":"index response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}},"summary":"This is index action summary","tags":["home"],"produces":["application/json"]},"post":{"description":"Create action","operationId":"homeTest/create","parameters":[{"name":"in","required":true,"description":"create body parameter","in":"body","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}],"responses":{"200":{"description":"create response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}},"summary":"This is create action summary","tags":["home"],"consumes":["application/json"]}},"/api/v1/homes/new":{"get":{"description":"New action","operationId":"homeTest/new","parameters":[{"name":"in","required":true,"description":"new body parameter","in":"body","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}],"responses":{"200":{"description":"new response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}},"summary":"This is new action summary","tags":["home"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]}},"/api/v1/homes/{id}":{"get":{"description":"Show action","operationId":"homeTest/show","parameters":[{"name":"id","required":true,"description":"show path parameter","in":"path","type":"string"}],"responses":{"200":{"description":"show response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}},"summary":"This is show action summary","tags":["home"],"produces":["application/json"]},"patch":{"description":"Edit action","operationId":"homeTest/edit","parameters":[{"name":"id","required":true,"description":"edit path parameter","in":"path","type":"string"},{"name":"in","required":true,"description":"edit body parameter","in":"body","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}],"responses":{"200":{"description":"edit response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}},"summary":"This is edit action summary","tags":["home"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]},"put":{"description":"Update action","operationId":"homeTest/update","parameters":[{"name":"id","required":true,"description":"update path parameter","in":"path","type":"string"},{"name":"id","required":true,"description":"update body parameter","in":"body","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}],"responses":{"200":{"description":"update response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}},"summary":"This is update action summary","tags":["home"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]},"delete":{"description":"Destory action","operationId":"homeTest/destory","parameters":[{"name":"id","required":true,"description":"destory path parameter","in":"path","type":"string"}],"responses":{"200":{"description":"destory response","schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"no":{"type":"string"}},"required":["name","address","no"],"additionalProperties":false}}},"summary":"This is destory action summary","tags":["home"],"consumes":["application/json"],"produces":["application/json"]}},"/api/v1/users":{"get":{"description":"Index action","operationId":"v1.users/index","parameters":[{"name":"index","required":true,"description":"index query parameter","in":"query","type":"string"}],"responses":{"200":{"description":"index response","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}},"summary":"This is index action summary","tags":["user"],"produces":["application/json"]},"post":{"description":"Create action","operationId":"v1.users/create","parameters":[{"name":"in","required":true,"description":"create body parameter","in":"body","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}],"responses":{"200":{"description":"create response","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}},"summary":"This is create action summary","tags":["user"],"consumes":["application/json"]}},"/api/v1/users/new":{"get":{"description":"New action","operationId":"v1.users/new","parameters":[{"name":"in","required":true,"description":"new body parameter","in":"body","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}],"responses":{"200":{"description":"new response","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}},"summary":"This is new action summary","tags":["user"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]}},"/api/v1/users/{id}":{"get":{"description":"Show action","operationId":"v1.users/show","parameters":[{"name":"id","required":true,"description":"show path parameter","in":"path","type":"string"}],"responses":{"200":{"description":"show response","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}},"summary":"This is show action summary","tags":["user"],"produces":["application/json"]},"post":{"description":"Update action","operationId":"v1.users/update","parameters":[{"name":"id","required":true,"description":"update path parameter","in":"path","type":"string"},{"name":"id","required":true,"description":"update body parameter","in":"body","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}],"responses":{"200":{"description":"update response","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}},"summary":"This is update action summary","tags":["user"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]},"delete":{"description":"Destory action","operationId":"v1.users/destory","parameters":[{"name":"id","required":true,"description":"destory path parameter","in":"path","type":"string"}],"responses":{"200":{"description":"destory response","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}},"summary":"This is destory action summary","tags":["user"],"consumes":["application/json"],"produces":["application/json"]}},"/api/v1/users/{id}/edit":{"get":{"description":"Edit action","operationId":"v1.users/edit","parameters":[{"name":"id","required":true,"description":"edit path parameter","in":"path","type":"string"},{"name":"in","required":true,"description":"edit body parameter","in":"body","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}],"responses":{"200":{"description":"edit response","schema":{"type":"object","properties":{"id":{"$ref":"schema.definition#/int"},"name":{"type":"string"},"password":{"type":"string"}},"required":["name","password","id"],"$async":true,"additionalProperties":false}}},"summary":"This is edit action summary","tags":["user"],"consumes":["application/x-www-form-urlencoded"],"produces":["application/json"]}}},"schemes":["https","http"],"basePath":"/","consumes":["application/json"],"produces":["application/json"]} -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = (app) => { 4 | const {router, controller} = app; 5 | 6 | router.prefix('/api/v1'); 7 | 8 | // Require style router 9 | require('./router/admin')(app); 10 | 11 | // RESTful style router 12 | router.resources('posts', '/posts', controller.posts); 13 | router.resources('users', '/users', controller.v1.users); 14 | 15 | // Common style router 16 | router.get('/homes', controller.homeTest.index); 17 | router.get('/homes/new', controller.homeTest.new); 18 | router.get('/homes/:id', controller.homeTest.show); 19 | router.patch('/homes/:id', controller.homeTest.edit); 20 | router.post('/homes', controller.homeTest.create); 21 | router.put('/homes/:id', controller.homeTest.update); 22 | router.delete('/homes/:id', controller.homeTest.destory); 23 | }; 24 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/router/admin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = (app) => { 4 | const {router, controller} = app; 5 | 6 | // Common style router 7 | app.router.get('/admin', app.controller.adminTest.index); 8 | router.get('newAdmin', '/admin/new', controller.adminTest.new); 9 | router.get('newShow', '/admin/:id', controller.adminTest.show); 10 | router.get('/admin/:id/edit', controller.adminTest.edit); 11 | router.post('/admin', controller.adminTest.create); 12 | router.put('/admin/:id', controller.adminTest.update); 13 | router.delete('/admin/:id', controller.adminTest.destory); 14 | }; 15 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/schema/admin_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | type: 'object', 5 | properties: { 6 | id: { 7 | type: 'string', 8 | }, 9 | name: { 10 | $ref: 'schema.definition#/int', 11 | }, 12 | telephone: { 13 | type: 'string', 14 | }, 15 | }, 16 | required: ['name', 'telephone', 'id'], 17 | additionalProperties: false, 18 | }; 19 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/schema/definitions/id.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | type: 'string', 5 | }; 6 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/schema/definitions/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | type: 'string', 5 | }; 6 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/schema/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | type: 'object', 5 | properties: { 6 | name: { 7 | type: 'string', 8 | }, 9 | address: { 10 | type: 'string', 11 | }, 12 | no: { 13 | type: 'string', 14 | }, 15 | }, 16 | required: [ 'name', 'address', 'no' ], 17 | additionalProperties: false, 18 | }; 19 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/app/schema/user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const User = { 4 | type: 'object', 5 | properties: { 6 | id: { 7 | $ref: 'schema.definition#/int', 8 | }, 9 | name: { 10 | type: 'string', 11 | }, 12 | password: { 13 | type: 'string', 14 | }, 15 | }, 16 | required: [ 'name', 'password', 'id' ], 17 | $async: true, 18 | additionalProperties: false, 19 | }; 20 | 21 | module.exports = User; 22 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.keys = '123456'; 4 | 5 | exports.static = { 6 | prefix: '/', 7 | }; 8 | 9 | exports.swaggerEgg = { 10 | swagger: { 11 | host: '', 12 | basePath: '/', 13 | schemes: ['https', 'http'], 14 | consumes: ['application/json'], 15 | produces: ['application/json'], 16 | tags: [ 17 | { 18 | name: 'admin', 19 | description: 'Everything about your admin', 20 | }, 21 | { 22 | name: 'user', 23 | description: 'Everything about your user', 24 | }, 25 | { 26 | name: 'home', 27 | description: 'Everything about your home', 28 | }, 29 | ], 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /test/fixtures/apps/swagger-egg-router-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swagger-egg-test", 3 | "version": "0.0.1", 4 | "description": "test description" 5 | } -------------------------------------------------------------------------------- /test/swagger-egg-static.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mock = require('egg-mock'); 4 | const globby = require('globby'); 5 | const path = require('path'); 6 | 7 | describe('test/swagger-egg.test.js', () => { 8 | let app; 9 | before(() => { 10 | app = mock.app({ 11 | baseDir: 'apps/swagger-egg-router-test', 12 | }); 13 | return app.ready(); 14 | }); 15 | 16 | after(() => app.close()); 17 | afterEach(mock.restore); 18 | 19 | it('should GET /index.html', () => { 20 | return app.httpRequest().get('/index.html').expect('Content-Type', 'text/html; charset=utf-8').expect(200); 21 | }); 22 | 23 | it('should GET /swagger.json', () => { 24 | const targetPath = path.join(app.config.baseDir, 'app/public/swagger'); 25 | const targetFileName = globby.sync('**/*.(json)', {cwd: targetPath}); 26 | return app 27 | .httpRequest() 28 | .get(`/swagger/${targetFileName[0]}`) 29 | .expect('Content-Type', 'application/json; charset=utf-8') 30 | .expect(200); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/swagger-egg.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mock = require('egg-mock'); 4 | const path = require('path'); 5 | 6 | describe('test/swagger-egg.test.js', () => { 7 | let app; 8 | before(() => { 9 | app = mock.app({ 10 | baseDir: 'apps/swagger-egg-router-test', 11 | }); 12 | return app.ready(); 13 | }); 14 | 15 | after(() => app.close()); 16 | afterEach(mock.restore); 17 | 18 | it('should GET /homes', () => { 19 | return app 20 | .httpRequest() 21 | .get('/api/v1/homes') 22 | .expect('hi, index action' + app.plugins.swaggerEgg.name) 23 | .expect(200); 24 | }); 25 | 26 | it('should GET swagger info', () => { 27 | const filePath = path.join(app.config.baseDir, './app/schema/user.js'); 28 | const userSchemaString = require(filePath); 29 | return app.httpRequest().get('/api/v1/users').expect(JSON.stringify(userSchemaString)).expect(200); 30 | }); 31 | }); 32 | --------------------------------------------------------------------------------