diff --git a/package-lock.json b/package-lock.json index 2a3168a..571244c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,9 @@ "express": "^4.18.2", "express-rate-limit": "^7.1.0", "morgan": "^1.10.0", - "pug": "^3.0.2" + "pug": "^3.0.2", + "swagger-jsdoc": "^6.2.8", + "swagger-ui-express": "^5.0.0" }, "devDependencies": { "jest": "^29.4.3", @@ -34,6 +36,62 @@ "node": ">=6.0.0" } }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", + "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, + "node_modules/@apidevtools/json-schema-ref-parser/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/@apidevtools/json-schema-ref-parser/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^9.0.6", + "@apidevtools/openapi-schemas": "^2.0.4", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "z-schema": "^5.0.1" + }, + "peerDependencies": { + "openapi-types": ">=7" + } + }, "node_modules/@babel/code-frame": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", @@ -1047,6 +1105,11 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" + }, "node_modules/@sinclair/typebox": { "version": "0.25.24", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", @@ -1145,6 +1208,11 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, "node_modules/@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", @@ -1388,8 +1456,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/basic-auth": { "version": "2.0.1", @@ -1420,7 +1487,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1501,6 +1567,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1685,11 +1756,18 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/commander": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", + "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", + "engines": { + "node": ">= 6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/constantinople": { "version": "4.0.1", @@ -1822,6 +1900,17 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/doctypes": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", @@ -1917,6 +2006,14 @@ "node": ">=4" } }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -2138,8 +2235,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.2", @@ -2383,7 +2479,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -3344,6 +3439,21 @@ "node": ">=8" } }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3469,7 +3579,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3652,7 +3761,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -3672,6 +3780,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "peer": true + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3762,7 +3876,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4390,6 +4503,74 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger-jsdoc": { + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", + "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==", + "dependencies": { + "commander": "6.2.0", + "doctrine": "3.0.0", + "glob": "7.1.6", + "lodash.mergewith": "^4.6.2", + "swagger-parser": "^10.0.3", + "yaml": "2.0.0-1" + }, + "bin": { + "swagger-jsdoc": "bin/swagger-jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/swagger-jsdoc/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", + "dependencies": { + "@apidevtools/swagger-parser": "10.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swagger-ui-dist": { + "version": "5.11.8", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.8.tgz", + "integrity": "sha512-IfPtCPdf6opT5HXrzHO4kjL1eco0/8xJCtcs7ilhKuzatrpF2j9s+3QbOag6G3mVFKf+g+Ca5UG9DquVUs2obA==" + }, + "node_modules/swagger-ui-express": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.0.tgz", + "integrity": "sha512-tsU9tODVvhyfkNSvf03E6FAk+z+5cU3lXAzMy6Pv4av2Gt2xA0++fogwC4qo19XuFf6hdxevPuVCSKFuMHJhFA==", + "dependencies": { + "swagger-ui-dist": ">=5.0.0" + }, + "engines": { + "node": ">= v0.10.32" + }, + "peerDependencies": { + "express": ">=4.0.0 || >=5.0.0-beta" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -4556,6 +4737,14 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true }, + "node_modules/validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -4630,8 +4819,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "4.0.2", @@ -4661,6 +4849,14 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "2.0.0-1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", + "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==", + "engines": { + "node": ">= 6" + } + }, "node_modules/yargs": { "version": "17.7.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", @@ -4699,6 +4895,34 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/z-schema": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", + "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "commander": "^9.4.1" + } + }, + "node_modules/z-schema/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "optional": true, + "engines": { + "node": "^12.20.0 || >=14" + } } }, "dependencies": { @@ -4712,6 +4936,55 @@ "@jridgewell/trace-mapping": "^0.3.9" } }, + "@apidevtools/json-schema-ref-parser": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", + "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", + "requires": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + } + } + }, + "@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==" + }, + "@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" + }, + "@apidevtools/swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", + "requires": { + "@apidevtools/json-schema-ref-parser": "^9.0.6", + "@apidevtools/openapi-schemas": "^2.0.4", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "z-schema": "^5.0.1" + } + }, "@babel/code-frame": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", @@ -5494,6 +5767,11 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" + }, "@sinclair/typebox": { "version": "0.25.24", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", @@ -5592,6 +5870,11 @@ "@types/istanbul-lib-report": "*" } }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, "@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", @@ -5784,8 +6067,7 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "basic-auth": { "version": "2.0.1", @@ -5812,7 +6094,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5868,6 +6149,11 @@ "get-intrinsic": "^1.0.2" } }, + "call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5993,11 +6279,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "commander": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", + "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "constantinople": { "version": "4.0.1", @@ -6099,6 +6389,14 @@ "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", "dev": true }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, "doctypes": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", @@ -6169,6 +6467,11 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -6347,8 +6650,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "2.3.2", @@ -6516,7 +6818,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -7252,6 +7553,21 @@ "p-locate": "^4.1.0" } }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -7346,7 +7662,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7487,7 +7802,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "requires": { "wrappy": "1" } @@ -7501,6 +7815,12 @@ "mimic-fn": "^2.1.0" } }, + "openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "peer": true + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7562,8 +7882,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -8054,6 +8373,55 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, + "swagger-jsdoc": { + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", + "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==", + "requires": { + "commander": "6.2.0", + "doctrine": "3.0.0", + "glob": "7.1.6", + "lodash.mergewith": "^4.6.2", + "swagger-parser": "^10.0.3", + "yaml": "2.0.0-1" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", + "requires": { + "@apidevtools/swagger-parser": "10.0.3" + } + }, + "swagger-ui-dist": { + "version": "5.11.8", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.8.tgz", + "integrity": "sha512-IfPtCPdf6opT5HXrzHO4kjL1eco0/8xJCtcs7ilhKuzatrpF2j9s+3QbOag6G3mVFKf+g+Ca5UG9DquVUs2obA==" + }, + "swagger-ui-express": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.0.tgz", + "integrity": "sha512-tsU9tODVvhyfkNSvf03E6FAk+z+5cU3lXAzMy6Pv4av2Gt2xA0++fogwC4qo19XuFf6hdxevPuVCSKFuMHJhFA==", + "requires": { + "swagger-ui-dist": ">=5.0.0" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -8170,6 +8538,11 @@ } } }, + "validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -8223,8 +8596,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "write-file-atomic": { "version": "4.0.2", @@ -8248,6 +8620,11 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "yaml": { + "version": "2.0.0-1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", + "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==" + }, "yargs": { "version": "17.7.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", @@ -8274,6 +8651,25 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true + }, + "z-schema": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", + "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", + "requires": { + "commander": "^9.4.1", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "dependencies": { + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "optional": true + } + } } } } diff --git a/package.json b/package.json index 990af87..486d35f 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,9 @@ "express": "^4.18.2", "express-rate-limit": "^7.1.0", "morgan": "^1.10.0", - "pug": "^3.0.2" + "pug": "^3.0.2", + "swagger-jsdoc": "^6.2.8", + "swagger-ui-express": "^5.0.0" }, "devDependencies": { "jest": "^29.4.3", diff --git a/src/index.js b/src/index.js index 629611c..9d8e4c5 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,8 @@ const fs = require('fs'); const path = require('path'); const cors = require('cors'); const express = require('express'); +const swaggerUI = require('swagger-ui-express'); +const swaggerSpec = require('./swagger'); const morgan = require('morgan'); const { rateLimit } = require('express-rate-limit'); require('dotenv').config(); @@ -28,6 +30,8 @@ app.use(express.urlencoded({ extended: false })); app.use(morgan('combined')); app.use(limiter); +app.use('/swagger', swaggerUI.serve, swaggerUI.setup(swaggerSpec)); + app.get('/', (req, res) => { const images = fs.readdirSync(path.join(__dirname, 'public', 'assets')); res.render('index', { @@ -43,10 +47,6 @@ app.get('/examples', (req, res) => { res.render('examples'); }); -app.get('/url-creator', (req, res) => { - res.sendFile(path.join(__dirname, 'views', 'url-creator.html')); -}); - app.use('/api/v1', require('./v1/routes')); app.all('*', (req, res, next) => { diff --git a/src/swagger.js b/src/swagger.js new file mode 100644 index 0000000..bbbb851 --- /dev/null +++ b/src/swagger.js @@ -0,0 +1,37 @@ +const swaggerJSDoc = require('swagger-jsdoc'); + +const swaggerDefinition = { + openapi: '3.0.0', + info: { + title: 'Turkiye API', + version: '1.0.0', + description: 'REST API for provinces and districts of Turkiye', + license: { + name: 'MIT License', + url: 'https://github.com/ubeydeozdmr/turkiye-api/blob/main/LICENSE', + }, + contact: { + name: 'Ubeyde Emir Özdemir', + url: 'https://ubeyde.me/', + email: 'ubeydeozdmr@gmail.com', + }, + }, + servers: [ + { + url: 'http://localhost:8181/api/v1/', + description: 'Development server', + }, + { + url: 'https://turkiyeapi.dev/api/v1/', + description: 'Production server', + }, + ], +}; + +const options = { + swaggerDefinition, + apis: ['./src/v1/routes.js'], +}; + +const swaggerSpec = swaggerJSDoc(options); +module.exports = swaggerSpec; diff --git a/src/v1/routes.js b/src/v1/routes.js index 2f2203a..8f5f7db 100644 --- a/src/v1/routes.js +++ b/src/v1/routes.js @@ -3,15 +3,1000 @@ const controller = require('./controller'); const router = express.Router(); +/** + * @swagger + * /provinces: + * get: + * summary: Get all provinces. + * description: Get all provinces. + * parameters: + * - in: query + * name: name + * description: The province name. + * schema: + * type: string + * - in: query + * name: minPopulation + * description: The minimum population of the province. + * schema: + * type: number + * - in: query + * name: maxPopulation + * description: The maximum population of the province. + * schema: + * type: number + * - in: query + * name: isMetropolitan + * description: The province is metropolitan or not. + * schema: + * type: boolean + * - in: query + * name: offset + * description: The offset of the provinces list. + * schema: + * type: number + * - in: query + * name: limit + * description: The limit of the provinces list. + * schema: + * type: number + * - in: query + * name: fields + * description: The fields to be returned. (comma separated) + * schema: + * type: string + * - in: query + * name: sort + * description: The sorting of the provinces list. (put '-' before the field name for descending order) + * schema: + * type: string + * tags: + * - Provinces + * produces: + * - application/json + * responses: + * 200: + * description: A list of provinces. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: OK + * data: + * type: array + * items: + * type: object + * properties: + * id: + * type: number + * description: The province ID. + * example: 34 + * name: + * type: string + * description: The province name. + * example: İstanbul + * population: + * type: number + * description: The province population. + * example: 15655924 + * area: + * type: number + * description: The province area (in square meters). + * example: 5461 + * altitude: + * type: number + * description: The province altitude (in meters). + * example: 25 + * areaCode: + * type: array + * description: The province area codes. + * items: + * type: number + * example: 212, 216 + * isMetropolitan: + * type: boolean + * description: The province is metropolitan or not. + * example: true + * nuts: + * type: object + * description: The NUTS codes of the province. + * properties: + * nuts1: + * type: object + * description: The NUTS1 code of the province. + * properties: + * code: + * type: string + * example: TR1 + * name: + * type: object + * properties: + * en: + * type: string + * example: İstanbul + * tr: + * type: string + * example: İstanbul + * nuts2: + * type: object + * description: The NUTS2 code of the province. + * properties: + * code: + * type: string + * example: TR10 + * name: + * type: string + * example: İstanbul + * nuts3: + * type: string + * example: TR100 + * coordinates: + * type: object + * description: The province coordinates. + * properties: + * latitude: + * type: number + * example: 41.01384 + * longitude: + * type: number + * example: 28.94966 + * maps: + * type: object + * description: The province map links. + * properties: + * googleMaps: + * type: string + * example: https://goo.gl/maps/wKdwRFM4NW8Wm6ZZ8 + * openStreetMaps: + * type: string + * example: https://www.openstreetmap.org/relation/223474 + * region: + * type: object + * description: The region of the province. + * properties: + * en: + * type: string + * example: Marmara + * tr: + * type: string + * example: Marmara + * districts: + * type: array + * description: The districts of the province. + * items: + * type: object + * properties: + * id: + * type: number + * example: 1852 + * name: + * type: string + * example: Ümraniye + * population: + * type: number + * example: 723760 + * area: + * type: number + * example: 46 + * 404: + * description: Provinces not found. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Provinces not found. + * 405: + * description: Method not allowed. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Method not allowed. + */ +router.get('/provinces', controller.getProvinces); + +/** + * @swagger + * /provinces/{id}: + * get: + * summary: Get exact province. + * description: Get exact province. + * parameters: + * - in: path + * name: id + * required: true + * description: The province ID / plate number. + * schema: + * type: number + * - in: query + * name: fields + * description: The fields to be returned. (comma separated) + * schema: + * type: string + * - in: query + * name: extend + * description: Extend the response with additional data. (neighborhoods and villages) + * schema: + * type: boolean + * tags: + * - Provinces + * produces: + * - application/json + * responses: + * 200: + * description: The province. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: OK + * data: + * type: object + * properties: + * id: + * type: number + * example: 34 + * name: + * type: string + * example: İstanbul + * population: + * type: number + * example: 15655924 + * area: + * type: number + * example: 5461 + * altitude: + * type: number + * example: 25 + * areaCode: + * type: array + * items: + * type: number + * example: 212, 216 + * isMetropolitan: + * type: boolean + * example: true + * nuts: + * type: object + * properties: + * nuts1: + * type: object + * properties: + * code: + * type: string + * example: TR1 + * name: + * type: object + * properties: + * en: + * type: string + * example: İstanbul + * tr: + * type: string + * example: İstanbul + * nuts2: + * type: object + * properties: + * code: + * type: string + * example: TR10 + * name: + * type: string + * example: İstanbul + * nuts3: + * type: string + * example: TR100 + * coordinates: + * type: object + * properties: + * latitude: + * type: number + * example: 41.01384 + * longitude: + * type: number + * example: 28.94966 + * maps: + * type: object + * properties: + * googleMaps: + * type: string + * example: https://goo.gl/maps/wKdwRFM4NW8Wm6ZZ8 + * openStreetMaps: + * type: string + * example: https://www.openstreetmap.org/relation/223474 + * region: + * type: object + * properties: + * en: + * type: string + * example: Marmara + * tr: + * type: string + * example: Marmara + * districts: + * type: array + * items: + * type: object + * properties: + * id: + * type: number + * example: 1852 + * name: + * type: string + * example: Ümraniye + * population: + * type: number + * example: 723760 + * area: + * type: number + * example: 46 + * 404: + * description: Province not found. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Province not found. + * 405: + * description: Method not allowed. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Method not allowed. + */ +router.get('/provinces/:id', controller.getExactProvince); + +/** + * @swagger + * /districts: + * get: + * summary: Get all districts. + * description: Get all districts. + * parameters: + * - in: query + * name: name + * description: The district name. + * schema: + * type: string + * - in: query + * name: minPopulation + * description: The minimum population of the district. + * schema: + * type: number + * - in: query + * name: maxPopulation + * description: The maximum population of the district. + * schema: + * type: number + * - in: query + * name: offset + * description: The offset of the districts list. + * schema: + * type: number + * - in: query + * name: limit + * description: The limit of the districts list. + * schema: + * type: number + * - in: query + * name: fields + * description: The fields to be returned. (comma separated) + * schema: + * type: string + * - in: query + * name: sort + * description: The sorting of the districts list. (put '-' before the field name for descending order) + * schema: + * type: string + * tags: + * - Districts + * produces: + * - application/json + * responses: + * 200: + * description: A list of districts. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: OK + * data: + * type: array + * items: + * type: object + * properties: + * provinceId: + * type: number + * example: 28 + * id: + * type: number + * example: 1272 + * province: + * type: string + * example: Giresun + * name: + * type: string + * example: Dereli + * population: + * type: number + * example: 19308 + * area: + * type: number + * example: 849 + * 404: + * description: District not found. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: District not found. + * 405: + * description: Method not allowed. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Method not allowed. + */ +router.get('/districts', controller.getDistricts); + +/** + * @swagger + * /districts/{id}: + * get: + * summary: Get exact district. + * description: Get exact district. + * parameters: + * - in: path + * name: id + * required: true + * description: The district ID. + * schema: + * type: number + * - in: query + * name: fields + * description: The fields to be returned. (comma separated) + * schema: + * type: string + * tags: + * - Districts + * produces: + * - application/json + * responses: + * 200: + * description: The district. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: OK + * data: + * type: object + * properties: + * provinceId: + * type: number + * example: 28 + * id: + * type: number + * example: 1272 + * provinceName: + * type: string + * example: Giresun + * name: + * type: string + * example: Dereli + * population: + * type: number + * example: 19308 + * area: + * type: number + * example: 849 + * neighborhoods: + * type: array + * items: + * type: object + * properties: + * id: + * type: number + * example: 30780 + * name: + * type: string + * example: Kuşluhan + * population: + * type: number + * example: 886 + * villages: + * type: array + * items: + * type: object + * properties: + * id: + * type: number + * example: 14547 + * name: + * type: string + * example: Küçükahmet + * population: + * type: number + * example: 278 + * 404: + * description: District not found. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: District not found. + * 405: + * description: Method not allowed. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Method not allowed. + */ +router.get('/districts/:id', controller.getExactDistrict); + +/** + * @swagger + * /neighborhoods: + * get: + * summary: Get all neighborhoods. + * description: Get all neighborhoods. + * parameters: + * - in: query + * name: name + * description: The neighborhood name. + * schema: + * type: string + * - in: query + * name: minPopulation + * description: The minimum population of the neighborhood. + * schema: + * type: number + * - in: query + * name: maxPopulation + * description: The maximum population of the neighborhood. + * schema: + * type: number + * - in: query + * name: offset + * description: The offset of the neighborhoods list. + * schema: + * type: number + * - in: query + * name: limit + * description: The limit of the neighborhoods list. + * schema: + * type: number + * - in: query + * name: fields + * description: The fields to be returned. (comma separated) + * schema: + * type: string + * - in: query + * name: sort + * description: The sorting of the neighborhoods list. (put '-' before the field name for descending order) + * schema: + * type: string + * tags: + * - Neighborhoods + * produces: + * - application/json + * responses: + * 200: + * description: A list of neighborhoods. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: OK + * data: + * type: array + * items: + * type: object + * properties: + * provinceId: + * type: number + * example: 28 + * districtId: + * type: number + * example: 1272 + * id: + * type: number + * example: 30780 + * province: + * type: string + * example: Giresun + * district: + * type: string + * example: Dereli + * name: + * type: string + * example: Kuşluhan + * population: + * type: number + * example: 886 + * 404: + * description: Neighborhoods not found. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Neighborhoods not found. + * 405: + * description: Method not allowed. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Method not allowed. + */ +router.get('/neighborhoods', controller.getNeighborhoods); + +/** + * @swagger + * /neighborhoods/{id}: + * get: + * summary: Get exact neighborhood. + * description: Get exact neighborhood. + * parameters: + * - in: path + * name: id + * required: true + * description: The neighborhood ID. + * schema: + * type: number + * - in: query + * name: fields + * description: The fields to be returned. (comma separated) + * schema: + * type: string + * tags: + * - Neighborhoods + * produces: + * - application/json + * responses: + * 200: + * description: The neighborhood. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: OK + * data: + * type: object + * properties: + * provinceId: + * type: number + * example: 28 + * districtId: + * type: number + * example: 1272 + * id: + * type: number + * example: 30780 + * province: + * type: string + * example: Giresun + * district: + * type: string + * example: Dereli + * name: + * type: string + * example: Kuşluhan + * population: + * type: number + * example: 886 + * 404: + * description: Neighborhood not found. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Neighborhood not found. + * 405: + * description: Method not allowed. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Method not allowed. + */ +router.get('/neighborhoods/:id', controller.getExactNeighborhood); + +/** + * @swagger + * /villages: + * get: + * summary: Get all villages. + * description: Get all villages. + * parameters: + * - in: query + * name: name + * description: The village name. + * schema: + * type: string + * - in: query + * name: minPopulation + * description: The minimum population of the village. + * schema: + * type: number + * - in: query + * name: maxPopulation + * description: The maximum population of the village. + * schema: + * type: number + * - in: query + * name: offset + * description: The offset of the villages list. + * schema: + * type: number + * - in: query + * name: limit + * description: The limit of the villages list. + * schema: + * type: number + * - in: query + * name: fields + * description: The fields to be returned. (comma separated) + * schema: + * type: string + * - in: query + * name: sort + * description: The sorting of the villages list. (put '-' before the field name for descending order) + * schema: + * type: string + * tags: + * - Villages + * produces: + * - application/json + * responses: + * 200: + * description: A list of villages. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: OK + * data: + * type: array + * items: + * type: object + * properties: + * provinceId: + * type: number + * example: 28 + * districtId: + * type: number + * example: 1272 + * neighborhoodId: + * type: number + * example: 30780 + * id: + * type: number + * example: 14547 + * province: + * type: string + * example: Giresun + * district: + * type: string + * example: Dereli + * name: + * type: string + * example: Küçükahmet + * population: + * type: number + * example: 278 + * 404: + * description: Villages not found. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Villages not found. + * 405: + * description: Method not allowed. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Method not allowed. + */ +router.get('/villages', controller.getVillages); + +/** + * @swagger + * /villages/{id}: + * get: + * summary: Get exact village. + * description: Get exact village. + * parameters: + * - in: path + * name: id + * required: true + * description: The village ID. + * schema: + * type: number + * - in: query + * name: fields + * description: The fields to be returned. (comma separated) + * schema: + * type: string + * tags: + * - Villages + * produces: + * - application/json + * responses: + * 200: + * description: The village. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: OK + * data: + * type: object + * properties: + * provinceId: + * type: number + * example: 28 + * districtId: + * type: number + * example: 1272 + * id: + * type: number + * example: 14547 + * province: + * type: string + * example: Giresun + * district: + * type: string + * example: Dereli + * name: + * type: string + * example: Küçükahmet + * population: + * type: number + * example: 278 + * 404: + * description: Village not found. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Village not found. + * 405: + * description: Method not allowed. + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: ERROR + * error: + * type: string + * example: Method not allowed. + */ +router.get('/villages/:id', controller.getExactVillage); + router - .get('/provinces', controller.getProvinces) - .get('/provinces/:id', controller.getExactProvince) - .get('/districts', controller.getDistricts) - .get('/districts/:id', controller.getExactDistrict) - .get('/neighborhoods', controller.getNeighborhoods) - .get('/neighborhoods/:id', controller.getExactNeighborhood) - .get('/villages', controller.getVillages) - .get('/villages/:id', controller.getExactVillage) .get('*', (req, res) => { res.status(404).json({ status: 'ERROR', diff --git a/src/views/docs.pug b/src/views/docs.pug index 05d3d91..37066d2 100644 --- a/src/views/docs.pug +++ b/src/views/docs.pug @@ -257,6 +257,9 @@ block content p | If you want to see API features as Postman documentation, you can a(target='_blank' href='https://documenter.getpostman.com/view/19561492/UzBguVHM') click here. + p + | If you want to see API features as Swagger documentation, you can + a(target='_blank' href='https://turkiyeapi.dev/swagger') click here. p | For explanation of the API in Turkish language, you can a(target='_blank' href='https://gist.github.com/ubeydeozdmr/e94ea5a1929805988b803ecb682c623a') click here.