From b6a756f274d477e7e5f3bbdfa65a036b03b98344 Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 12:33:17 +0200 Subject: [PATCH 01/15] feat - added support for defining openapi paths spec for non lambda apis --- .github/workflows/npm-publish.yml | 24 ++++++---------- README.md | 48 +++++++++++++++++++++++++++++++ package-lock.json | 45 ++++++++++++++++------------- src/definitionGenerator.js | 20 +++++++++++-- 4 files changed, 98 insertions(+), 39 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index e739a1d..d416e80 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -8,26 +8,18 @@ on: types: [created] jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 20 - - run: npm ci - # - run: npm test - publish-npm: - needs: build runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x] steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: 20 - registry-url: https://registry.npmjs.org/ + node-version: ${{ matrix.node-version }} + registry-url: https://npm.pkg.github.com/ - run: npm ci - run: npm publish env: - NODE_AUTH_TOKEN: ${{secrets.npm_token}} + NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/README.md b/README.md index 5a64520..1246010 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ Options: | tags[].externalDocs.url | `custom.documentation.tags.externalDocumentation.url` | | tags[].externalDocs.description | `custom.documentation.tags.externalDocumentation.description` | | tags[].externalDocs.x- | `custom.documentation.tags.externalDocumentation.x-` if extended specifications provided | +| paths | `custom.documentation.paths` OpenAPI paths that are not backed by Lambda functions | | path[path] | functions.functions.events.[http OR httpApi].path | | path[path].servers[].description | functions.functions.servers.description | | path[path].servers[].url | functions.functions.servers.url | @@ -545,6 +546,53 @@ functions: application/json: ${file(create_request.json)} ``` +#### Adding non-Lambda endpoints with `paths` + +You can add OpenAPI paths that are not backed by Lambda functions using the `paths` field under `custom.documentation`. This is useful for documenting endpoints handled outside of Serverless functions, such as static assets, third-party integrations, or legacy APIs. + +The `paths` field should follow the [OpenAPI Paths Object](https://spec.openapis.org/oas/v3.0.4#paths-object) structure. Any paths defined here will be merged into the generated OpenAPI document alongside Lambda-backed endpoints. + +**Example:** + +```yml +custom: + documentation: + title: My API + version: "1" + paths: + /static/health: + get: + summary: Health check for static endpoint + description: Returns status of the static service + responses: + "200": + description: OK + content: + application/json: + schema: + type: object + properties: + status: + type: string + example: ok + /external/webhook: + post: + summary: Webhook endpoint + description: Receives webhook calls from external service + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + event: + type: string + responses: + "204": + description: No Content +``` + #### Functions To define the documentation for a given function event, you need to create a `documentation` attribute for your `http` or `httpApi` event in your `serverless.yml` file. diff --git a/package-lock.json b/package-lock.json index cfeb455..cb704e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -484,20 +484,22 @@ } }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1045,10 +1047,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1445,6 +1448,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2655,6 +2659,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -3369,20 +3374,20 @@ "dev": true }, "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "requires": { "balanced-match": "^1.0.0" } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browser-stdout": { @@ -3771,9 +3776,9 @@ "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==" }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" diff --git a/src/definitionGenerator.js b/src/definitionGenerator.js index 9bfb223..7f8542d 100644 --- a/src/definitionGenerator.js +++ b/src/definitionGenerator.js @@ -127,9 +127,13 @@ class DefinitionGenerator { } } - await this.createPaths().catch((err) => { - throw err; - }); + await this.createPaths() + .then(() => { + this.mergeExistingPaths(); + }) + .catch((err) => { + throw err; + }); this.cleanupLinks(); @@ -266,6 +270,16 @@ class DefinitionGenerator { Object.assign(this.openAPI, { paths }); } + mergeExistingPaths() { + const paths = this.serverless.service.custom.documentation.paths; + + const origPaths = this.openAPI.paths || {}; + + if (paths) { + Object.assign(this.openAPI, { paths: { ...origPaths, ...paths } }); + } + } + createServers(servers) { const serverDoc = servers; const newServers = []; From 30e55a73ec466d9a6c852e815397565fb6c7e35a Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 12:42:57 +0200 Subject: [PATCH 02/15] feat - updated node.yml gh workflow --- .github/workflows/node.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 0fcd3be..0a1b32e 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -15,13 +15,13 @@ jobs: strategy: matrix: - node-version: [20.x, 22.x] + node-version: [20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" From 188f6869909f6daa7a701c0faa8485fcc255b0ce Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 12:57:07 +0200 Subject: [PATCH 03/15] fix - fixed repository url --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 4ec37dd..b201834 100644 --- a/package.json +++ b/package.json @@ -38,10 +38,10 @@ }, "repository": { "type": "git", - "url": "https://github.com/JaredCE/serverless-openapi-documenter.git" + "url": "https://github.com/tellihealth/serverless-openapi-documenter.git" }, "bugs": { - "url": "https://github.com/JaredCE/serverless-openapi-documenter/issues" + "url": "https://github.com/tellihealth/serverless-openapi-documenter/issues" }, "license": "MIT", "dependencies": { @@ -62,4 +62,4 @@ "nock": "^14.0.2", "sinon": "^20.0.0" } -} +} \ No newline at end of file From 9ba9be23433c3c718251f7744d44c371e8355452 Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 12:58:55 +0200 Subject: [PATCH 04/15] feat - incrase version on release --- .github/workflows/npm-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index d416e80..945fff5 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -20,6 +20,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://npm.pkg.github.com/ - run: npm ci + - run: npm version minor - run: npm publish env: NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} From 357566fb97ec5a2fb72d17b34acf607a4d5def72 Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 13:04:13 +0200 Subject: [PATCH 05/15] fix - added git config for bot --- .github/workflows/npm-publish.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 945fff5..a2f0b6d 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -20,6 +20,9 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://npm.pkg.github.com/ - run: npm ci + - run: | + git config --global user.email "ci-bot@tellihealth.com" + git config --global user.name "CI Bot" - run: npm version minor - run: npm publish env: From 1a68e426a19070f98785989fa770905328466bfc Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 13:40:10 +0200 Subject: [PATCH 06/15] feat - updated package name --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b201834..f4183d6 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "serverless-openapi-documenter", + "name": "@tellihealth/serverless-openapi-documenter", "version": "0.0.113", "description": "Generate OpenAPI v3 documentation and Postman Collections from your Serverless Config", "main": "index.js", From a99b00f431e8b6257daf8ee0c13cf5a8775abf44 Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 13:46:47 +0200 Subject: [PATCH 07/15] feat - updated README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1246010..8a8e551 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,14 @@ To add this plugin to your package.json: **Using npm:** ```bash -npm install --save-dev serverless-openapi-documenter +npm install --save-dev @telllihealth/serverless-openapi-documenter ``` Next you need to add the plugin to the `plugins` section of your `serverless.yml` file. ```yml plugins: - - serverless-openapi-documenter + - @telllihealth/serverless-openapi-documenter ``` > Note: Add this plugin _after_ `serverless-offline` to prevent issues with `String.replaceAll` being overridden incorrectly. From 02a226762e402a79ad3d0fa085b1e0f34d8ced39 Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 13:58:31 +0200 Subject: [PATCH 08/15] feat - updated release worfklows --- .github/workflows/bump-version.yml | 29 +++++++++++++++++++++++++++++ .github/workflows/node.yml | 2 ++ 2 files changed, 31 insertions(+) create mode 100644 .github/workflows/bump-version.yml diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml new file mode 100644 index 0000000..bdd47aa --- /dev/null +++ b/.github/workflows/bump-version.yml @@ -0,0 +1,29 @@ +name: Bump Version on Merge to Main + +on: + push: + branches: [main] + +jobs: + bump-version: + runs-on: ubuntu-latest + + if: "!contains(github.event.head_commit.message, 'ci: bump version')" # skip version bump commits + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Bump version (patch) + run: | + git config --global user.email "ci-bot@tellihealth.com" + git config --global user.name "CI Bot" + npm version patch -m "ci: bump version to %s" + git push origin main --follow-tags diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 0a1b32e..da609b6 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -18,6 +18,8 @@ jobs: node-version: [20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + if: "!contains(github.event.head_commit.message, 'ci: bump version')" # skip version bump commits + steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} From 14ab127f35a3f79a2cee4c05a4d7905ea5347eec Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 14:02:03 +0200 Subject: [PATCH 09/15] fix - fixed publish workflow --- .github/workflows/npm-publish.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index a2f0b6d..d416e80 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -20,10 +20,6 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://npm.pkg.github.com/ - run: npm ci - - run: | - git config --global user.email "ci-bot@tellihealth.com" - git config --global user.name "CI Bot" - - run: npm version minor - run: npm publish env: NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} From 7fdc893b606059f7f59ba0f77c8f6ef9236224fa Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Wed, 2 Jul 2025 14:27:15 +0200 Subject: [PATCH 10/15] fix - updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a8e551..91902f2 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Next you need to add the plugin to the `plugins` section of your `serverless.yml ```yml plugins: - - @telllihealth/serverless-openapi-documenter + - "@telllihealth/serverless-openapi-documenter" ``` > Note: Add this plugin _after_ `serverless-offline` to prevent issues with `String.replaceAll` being overridden incorrectly. From b53682a28bd0ec5bc0053966eb34e27ec2b5731c Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Thu, 3 Jul 2025 18:38:59 +0200 Subject: [PATCH 11/15] feat - little code refactoring --- src/definitionGenerator.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/definitionGenerator.js b/src/definitionGenerator.js index 7f8542d..cd26404 100644 --- a/src/definitionGenerator.js +++ b/src/definitionGenerator.js @@ -273,9 +273,9 @@ class DefinitionGenerator { mergeExistingPaths() { const paths = this.serverless.service.custom.documentation.paths; - const origPaths = this.openAPI.paths || {}; - if (paths) { + const origPaths = this.openAPI.paths || {}; + Object.assign(this.openAPI, { paths: { ...origPaths, ...paths } }); } } From 70dc5e1d26ab96fa6eb04577e2ce9c68ce0d0c57 Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Fri, 4 Jul 2025 09:11:00 +0200 Subject: [PATCH 12/15] feat - prepend basePath is domain manager plugin is being used --- src/definitionGenerator.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/definitionGenerator.js b/src/definitionGenerator.js index cd26404..f135c6a 100644 --- a/src/definitionGenerator.js +++ b/src/definitionGenerator.js @@ -259,6 +259,10 @@ class DefinitionGenerator { slashPath = `/${(event?.http?.path || event.httpApi?.path) ?? ""}`; } + const basePath = this.getBasePath(); + // append the base path so server is just the pure domain + slashPath = `/${basePath}${slashPath}`; + if (paths[slashPath]) { Object.assign(paths[slashPath], path); } else { @@ -280,6 +284,22 @@ class DefinitionGenerator { } } + /** + * @description Retrieves the basePath value if the domain manager plugin is used, allowing the server URL to be just the plain domain. The `basePath` will be prepended to each Lambda HTTP path. + * @returns {string} + */ + getBasePath() { + const plugins = this.serverless.service.plugins; + + let basePath = ""; + + if (plugins.includes("serverless-domain-manager")) { + basePath = this.serverless.service.custom.basePath || ""; + } + + return basePath; + } + createServers(servers) { const serverDoc = servers; const newServers = []; From 1d3c581f876c23b6ed1171b0f4cc1229ab2ef27c Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Fri, 4 Jul 2025 10:27:11 +0200 Subject: [PATCH 13/15] fix - fixed plugins selection --- src/definitionGenerator.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/definitionGenerator.js b/src/definitionGenerator.js index f135c6a..4510900 100644 --- a/src/definitionGenerator.js +++ b/src/definitionGenerator.js @@ -260,8 +260,11 @@ class DefinitionGenerator { } const basePath = this.getBasePath(); - // append the base path so server is just the pure domain - slashPath = `/${basePath}${slashPath}`; + + if (basePath) { + // append the base path so server is just the pure domain + slashPath = `/${basePath}${slashPath}`; + } if (paths[slashPath]) { Object.assign(paths[slashPath], path); @@ -289,7 +292,7 @@ class DefinitionGenerator { * @returns {string} */ getBasePath() { - const plugins = this.serverless.service.plugins; + const plugins = this.serverless.service.plugins || []; let basePath = ""; From 249812efeb51fdc10a0613407636d6089aabea4c Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Mon, 25 Aug 2025 17:06:06 +0200 Subject: [PATCH 14/15] CHANGE - added support for basePath --- README.md | 1 + src/definitionGenerator.js | 26 ++++++++----- test/helpers/serverless.js | 56 +++++++++++++++++++-------- test/unit/definitionGenerator.spec.js | 38 ++++++++++++++++++ 4 files changed, 95 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 91902f2..96f4418 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ Options: | tags[].externalDocs.url | `custom.documentation.tags.externalDocumentation.url` | | tags[].externalDocs.description | `custom.documentation.tags.externalDocumentation.description` | | tags[].externalDocs.x- | `custom.documentation.tags.externalDocumentation.x-` if extended specifications provided | +| basePath | `custom.documentation.basePath`Specifies the base path to prepend to all Lambda HTTP function paths in the generated OpenAPI specification | | paths | `custom.documentation.paths` OpenAPI paths that are not backed by Lambda functions | | path[path] | functions.functions.events.[http OR httpApi].path | | path[path].servers[].description | functions.functions.servers.description | diff --git a/src/definitionGenerator.js b/src/definitionGenerator.js index 4510900..980fc51 100644 --- a/src/definitionGenerator.js +++ b/src/definitionGenerator.js @@ -281,6 +281,18 @@ class DefinitionGenerator { const paths = this.serverless.service.custom.documentation.paths; if (paths) { + const basePath = this.getBasePath(); + + if (basePath) { + // check is paths's keys are not starting with `basePath` prefix and if set append it + for (const key of Object.keys(paths)) { + if (!key.startsWith(`/${basePath}`)) { + paths[`/${basePath}${key}`] = paths[key]; + delete paths[key]; + } + } + } + const origPaths = this.openAPI.paths || {}; Object.assign(this.openAPI, { paths: { ...origPaths, ...paths } }); @@ -288,19 +300,13 @@ class DefinitionGenerator { } /** - * @description Retrieves the basePath value if the domain manager plugin is used, allowing the server URL to be just the plain domain. The `basePath` will be prepended to each Lambda HTTP path. + * @description Retrieves the basePath value if set, allowing the server URL to be just the plain domain. The `basePath` will be prepended to each Lambda HTTP path. If `basePath` starts with a slash (/) returns the basePath without the leading slash. * @returns {string} */ getBasePath() { - const plugins = this.serverless.service.plugins || []; - - let basePath = ""; - - if (plugins.includes("serverless-domain-manager")) { - basePath = this.serverless.service.custom.basePath || ""; - } - - return basePath; + const basePath = + this.serverless.service.custom.documentation.basePath || ""; + return basePath.replace(/^\//, ""); } createServers(servers) { diff --git a/test/helpers/serverless.js b/test/helpers/serverless.js index fec3545..2417d82 100644 --- a/test/helpers/serverless.js +++ b/test/helpers/serverless.js @@ -1,19 +1,43 @@ -'use strict' +"use strict"; module.exports = { - processedInput: { - options: { - openApiVersion: '3.0.1' - } + processedInput: { + options: { + openApiVersion: "3.0.1", }, - service: { - service: 'myAPI', - custom: { - documentation: { - title: 'My new API', - description: 'This API does things', - version: '0.0.1' - } - } - } -} + }, + service: { + service: "myAPI", + custom: { + documentation: { + title: "My new API", + description: "This API does things", + version: "0.0.1", + basePath: "v1", + paths: { + "/test/path": { + post: { + tags: ["Ttest Api"], + summary: "Test Api", + parameters: [ + { + in: "path", + name: "id", + required: true, + schema: { + type: "string", + }, + }, + ], + responses: { + 204: { + description: "No content", + }, + }, + }, + }, + }, + }, + }, + }, +}; diff --git a/test/unit/definitionGenerator.spec.js b/test/unit/definitionGenerator.spec.js index 8f94c0a..27badd6 100644 --- a/test/unit/definitionGenerator.spec.js +++ b/test/unit/definitionGenerator.spec.js @@ -105,6 +105,44 @@ describe("DefinitionGenerator", () => { expect(expected.version).to.be.equal("3.0.0"); }); + it("should use the basePath when supplied", async function () { + const serverlessWithOpenAPIVersion = structuredClone(mockServerless); + const expected = new DefinitionGenerator( + serverlessWithOpenAPIVersion, + logger + ); + const serverlessWithOpenAPIVersion2 = structuredClone(mockServerless); + delete serverlessWithOpenAPIVersion2.service.custom.documentation + .basePath; + const expectedWithoutBasePath = new DefinitionGenerator( + serverlessWithOpenAPIVersion2, + logger + ); + + expected.mergeExistingPaths(); + expectedWithoutBasePath.mergeExistingPaths(); + + expect(expected.getBasePath()).to.be.equal( + serverlessWithOpenAPIVersion.service.custom.documentation.basePath + ); + expect( + Object.keys(expected.openAPI.paths).every((key) => + key.startsWith(`/${expected.getBasePath()}`) + ) + ).to.be.equal(true); + + expect(expectedWithoutBasePath.getBasePath()).to.be.equal(""); + expect( + Object.keys(expectedWithoutBasePath.openAPI.paths).every((key, idx) => + key.startsWith( + Object.keys( + serverlessWithOpenAPIVersion2.service.custom.documentation.paths + )[idx] + ) + ) + ).to.be.equal(true); + }); + it("should respect the version of openAPI when passed in", function () { const serverlessWithOpenAPIVersion = structuredClone(mockServerless); serverlessWithOpenAPIVersion.processedInput.options.openApiVersion = From 6f28af9dc406ef097822e68e35ba6a0df87afdd9 Mon Sep 17 00:00:00 2001 From: Simun Romic Date: Mon, 25 Aug 2025 17:18:12 +0200 Subject: [PATCH 15/15] CHANGE - added a new owasp definition --- src/owasp.js | 4 ++++ test/json/newOWASP.json | 6 +++++- test/unit/owasp.spec.js | 10 +++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/owasp.js b/src/owasp.js index 5189e5c..a1eb611 100644 --- a/src/owasp.js +++ b/src/owasp.js @@ -59,6 +59,9 @@ class OWASP { description: "The X-Content-Type-Options response HTTP header is a marker used by the server to indicate that the [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) advertised in the [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) headers should be followed and not be changed. The header allows you to avoid [MIME type sniffing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing) by saying that the MIME types are deliberately configured. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)", }, + "X-DNS-Prefetch-Control": { + description: "Controls DNS prefetching.", + }, "X-Frame-Options": { description: "The X-Frame-Options [HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP) response header can be used to indicate whether or not a browser should be allowed to render a page in a [](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/frame), [