From 18f8366259e123c4dfdb9b13250ad3e0b181e5c8 Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Sun, 13 Jul 2025 09:56:59 +0100 Subject: [PATCH 1/8] 0.0.115-beta.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2500ccf..c6daaf6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "serverless-openapi-documenter", - "version": "0.0.114", + "version": "0.0.115-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "serverless-openapi-documenter", - "version": "0.0.114", + "version": "0.0.115-beta.1", "license": "MIT", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.1.0", diff --git a/package.json b/package.json index c855cf8..21a896d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "serverless-openapi-documenter", - "version": "0.0.114", + "version": "0.0.115-beta.1", "description": "Generate OpenAPI v3 documentation and Postman Collections from your Serverless Config", "main": "index.js", "keywords": [ From e5d7da31cc4e8b94e39fbadbf80d384f77594d8a Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Sun, 13 Jul 2025 10:04:56 +0100 Subject: [PATCH 2/8] We shouldn't need to convert schemas for 3.1.x --- src/schemaHandler.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/schemaHandler.js b/src/schemaHandler.js index d66bc61..ccfb69d 100644 --- a/src/schemaHandler.js +++ b/src/schemaHandler.js @@ -15,6 +15,8 @@ class SchemaHandler { serverless.service?.provider?.apiGateway?.request?.schemas || {}; this.documentation = serverless.service.custom.documentation; this.openAPI = openAPI; + this.shouldConvert = true; + if (/(3\.1\.\d)/g(this.openAPI.openapi)) this.shouldConvert = false; this.modelReferences = {}; @@ -161,14 +163,20 @@ class SchemaHandler { `dereferenced model: ${JSON.stringify(dereferencedSchema)}` ); - this.logger.verbose(`converting model: ${name}`); - const convertedSchemas = SchemaConvertor.convert(dereferencedSchema, name); + if (this.shouldConvert) { + this.logger.verbose(`converting model: ${name}`); + const convertedSchemas = SchemaConvertor.convert( + dereferencedSchema, + name + ); - this.logger.verbose( - `converted schemas: ${JSON.stringify(convertedSchemas)}` - ); + this.logger.verbose( + `converted schemas: ${JSON.stringify(convertedSchemas)}` + ); + return convertedSchemas; + } - return convertedSchemas; + return dereferencedSchema; } async __dereferenceSchema(schema) { From beed295d29c27a495bfded5464347ad12864ce3f Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Sun, 13 Jul 2025 10:16:53 +0100 Subject: [PATCH 3/8] add to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 55fd985..86ab1b1 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ This will generate an OpenAPI V3 (up to v3.0.4) file for you from your serverless file. It can optionally generate a [Postman Collection V2](https://github.com/postmanlabs/openapi-to-postman) from the OpenAPI file for you too. This currently works for `http` and `httpApi` configurations. +If you are using the beta of 0.0.115, it will now try and create OpenAPI V3.1 (3.1.x) specs for you. Please see this [guide on migrating to V3.1](https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0) + Originally based off of: https://github.com/temando/serverless-openapi-documentation ## Install From 4ed4320a483d7a278ad694ac66af796bf9e031b1 Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Sun, 13 Jul 2025 10:43:31 +0100 Subject: [PATCH 4/8] adds tests and fixes case --- test/unit/schemaHandler.spec.js | 114 ++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 7 deletions(-) diff --git a/test/unit/schemaHandler.spec.js b/test/unit/schemaHandler.spec.js index d5a1cbc..4d08732 100644 --- a/test/unit/schemaHandler.spec.js +++ b/test/unit/schemaHandler.spec.js @@ -4,7 +4,9 @@ const fs = require("fs").promises; const path = require("path"); const expect = require("chai").expect; +const SchemaConvertor = require("json-schema-for-openapi"); const nock = require("nock"); +const sinon = require("sinon"); const modelsDocumentOG = require("../models/models/models.json"); const modelsAltDocumentOG = require("../models/models/models-alt.json"); @@ -36,7 +38,7 @@ describe(`SchemaHandler`, function () { ); const openAPISchema = { - version: "3.0.3", + openapi: "3.0.3", components: { schemas: {}, }, @@ -277,7 +279,7 @@ describe(`SchemaHandler`, function () { describe(`addModelsToOpenAPI`, function () { describe(`embedded simple schemas`, function () { - it(`should add the model to the openAPI schema`, async function () { + it(`should add the model to the OpenAPI schema`, async function () { Object.assign( mockServerless.service.custom.documentation, modelsDocument @@ -306,7 +308,7 @@ describe(`SchemaHandler`, function () { }); }); - it(`should add a model with references to the openAPI schema`, async function () { + it(`should add a model with references to the OpenAPI schema`, async function () { Object.assign( mockServerless.service.custom.documentation, modelsDocument @@ -379,7 +381,7 @@ describe(`SchemaHandler`, function () { }); }); - it(`should add a model with poorly dereferenced references to the openAPI schema`, async function () { + it(`should add a model with poorly dereferenced references to the OpenAPI schema`, async function () { Object.assign( mockServerless.service.custom.documentation, modelsDocument @@ -446,7 +448,7 @@ describe(`SchemaHandler`, function () { }); describe(`component references`, function () { - it(`should add schemas with component references to the openAPI schema`, async function () { + it(`should add schemas with component references to the OpenAPI schema`, async function () { Object.assign( mockServerless.service.custom.documentation, modelsDocument @@ -517,10 +519,86 @@ describe(`SchemaHandler`, function () { type: "string", }); }); + + it(`should add schemas with component references to the OpenAPI schema using OpenAPI 3.1`, async function () { + Object.assign( + mockServerless.service.custom.documentation, + modelsDocument + ); + + mockServerless.service.custom.documentation.models.push({ + name: "SuccessResponse", + contentType: "application/json", + schema: { + type: "array", + items: { + $ref: "#/components/schemas/Agency", + }, + }, + }); + + mockServerless.service.custom.documentation.models.push({ + name: "Agency", + contentType: "application/json", + schema: { + type: "string", + }, + }); + + openAPI.openapi = "3.1.0"; + + const schemaHandler = new SchemaHandler( + mockServerless, + openAPI, + logger + ); + + await schemaHandler.addModelsToOpenAPI(); + + expect(schemaHandler.openAPI).to.have.property("components"); + expect(schemaHandler.openAPI.components).to.have.property("schemas"); + expect(schemaHandler.openAPI.components.schemas).to.have.property( + "ErrorResponse" + ); + expect( + schemaHandler.openAPI.components.schemas.ErrorResponse + ).to.be.an("object"); + expect( + schemaHandler.openAPI.components.schemas.ErrorResponse + ).to.be.eql({ + type: "object", + properties: { error: { type: "string" } }, + }); + + expect(schemaHandler.openAPI.components.schemas).to.have.property( + "SuccessResponse" + ); + expect( + schemaHandler.openAPI.components.schemas.SuccessResponse + ).to.be.an("object"); + expect( + schemaHandler.openAPI.components.schemas.SuccessResponse + ).to.be.eql({ + type: "array", + items: { + $ref: "#/components/schemas/Agency", + }, + }); + + expect(schemaHandler.openAPI.components.schemas).to.have.property( + "Agency" + ); + expect(schemaHandler.openAPI.components.schemas.Agency).to.be.an( + "object" + ); + expect(schemaHandler.openAPI.components.schemas.Agency).to.be.eql({ + type: "string", + }); + }); }); describe(`other references`, function () { - it(`should add a model that is a webUrl to the openAPI schema`, async function () { + it(`should add a model that is a webUrl to the OpenAPI schema`, async function () { Object.assign( mockServerless.service.custom.documentation, modelsDocument @@ -589,7 +667,7 @@ describe(`SchemaHandler`, function () { }); }); - it(`should add a complex model that is a webUrl to the openAPI schema`, async function () { + it(`should add a complex model that is a webUrl to the OpenAPI schema`, async function () { Object.assign( mockServerless.service.custom.documentation, modelsDocument @@ -710,6 +788,28 @@ describe(`SchemaHandler`, function () { }); describe(`createSchema`, function () { + it(`does not convert schemas when using OpenAPI 3.1.x`, async function () { + Object.assign( + mockServerless.service.custom.documentation, + modelsDocument + ); + + openAPI.openapi = "3.1.0"; + + const schemaHandler = new SchemaHandler(mockServerless, openAPI, logger); + + const spy = sinon.spy(SchemaConvertor, "convert"); + + await schemaHandler.addModelsToOpenAPI(); + + const expected = await schemaHandler.createSchema("ErrorResponse"); + + expect(expected).to.be.equal("#/components/schemas/ErrorResponse"); + expect(spy.calledOnce).to.be.false; + + spy.restore(); + }); + it(`returns a reference to the schema when the schema already exists in components and we don't pass through a schema`, async function () { Object.assign( mockServerless.service.custom.documentation, From 7bcfa6e59f2b9dc055668a32169f6727829ce73b Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Sun, 13 Jul 2025 10:43:57 +0100 Subject: [PATCH 5/8] fixes casing of OpenAPI --- test/unit/definitionGenerator.spec.js | 11 ++++++----- test/unit/openAPIGenerator.spec.js | 10 +++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/test/unit/definitionGenerator.spec.js b/test/unit/definitionGenerator.spec.js index 65b76f9..950d024 100644 --- a/test/unit/definitionGenerator.spec.js +++ b/test/unit/definitionGenerator.spec.js @@ -38,7 +38,7 @@ describe("DefinitionGenerator", () => { expect(expected).to.be.an.instanceOf(DefinitionGenerator); }); - it("should default to version 3.0.0 of openAPI when openAPI version is not passed in", function () { + it("should default to version 3.0.0 of OpenAPI when OpenAPI version is not passed in", function () { const serverlessWithoutOpenAPIVersion = structuredClone(mockServerless); delete serverlessWithoutOpenAPIVersion.processedInput; let expected = new DefinitionGenerator( @@ -105,7 +105,7 @@ describe("DefinitionGenerator", () => { expect(expected.version).to.be.equal("3.0.0"); }); - it("should respect the version of openAPI when passed in", function () { + it("should respect the version of OpenAPI when passed in", function () { const serverlessWithOpenAPIVersion = structuredClone(mockServerless); serverlessWithOpenAPIVersion.processedInput.options.openApiVersion = "3.0.2"; @@ -157,7 +157,7 @@ describe("DefinitionGenerator", () => { }); describe("createInfo", () => { - it("should create openAPI info object correctly", function () { + it("should create OpenAPI info object correctly", function () { const definitionGenerator = new DefinitionGenerator( mockServerless, logger @@ -918,14 +918,15 @@ describe("DefinitionGenerator", () => { definitionGenerator.openAPI.components.securitySchemes ).to.have.property("x_amazon_api_key"); expect( - definitionGenerator.openAPI.components.securitySchemes.x_amazon_api_key + definitionGenerator.openAPI.components.securitySchemes + .x_amazon_api_key ).to.have.property("x-amazon-apigateway-authtype"); }); }); }); describe("createTags", () => { - it("should add tags to the openAPI object correctly", function () { + it("should add tags to the OpenAPI object correctly", function () { mockServerless.service.custom.documentation.tags = [{ name: "tag1" }]; const definitionGenerator = new DefinitionGenerator( diff --git a/test/unit/openAPIGenerator.spec.js b/test/unit/openAPIGenerator.spec.js index 4436083..cbffbcc 100644 --- a/test/unit/openAPIGenerator.spec.js +++ b/test/unit/openAPIGenerator.spec.js @@ -68,7 +68,7 @@ describe("OpenAPIGenerator", () => { }); describe("generationAndValidation", () => { - it("should correctly generate a valid openAPI document", async function () { + it("should correctly generate a valid OpenAPI document", async function () { const succSpy = sinon.spy(logOutput.log, "success"); const errSpy = sinon.spy(logOutput.log, "error"); @@ -99,7 +99,7 @@ describe("OpenAPIGenerator", () => { getFuncStub.reset(); }); - xit("should throw an error when trying to generate an invalid openAPI document", async function () { + xit("should throw an error when trying to generate an invalid OpenAPI document", async function () { const succSpy = sinon.spy(logOutput.log, "success"); const errSpy = sinon.spy(logOutput.log, "error"); @@ -135,7 +135,7 @@ describe("OpenAPIGenerator", () => { getFuncStub.reset(); }); - it("should correctly validate a valid openAPI document", async function () { + it("should correctly validate a valid OpenAPI document", async function () { const succSpy = sinon.spy(logOutput.log, "success"); const errSpy = sinon.spy(logOutput.log, "error"); @@ -168,7 +168,7 @@ describe("OpenAPIGenerator", () => { getFuncStub.reset(); }); - it("should throw an error when trying to validate an invalid openAPI document", async function () { + it("should throw an error when trying to validate an invalid OpenAPI document", async function () { const succSpy = sinon.spy(logOutput.log, "success"); const errSpy = sinon.spy(logOutput.log, "error"); @@ -212,7 +212,7 @@ describe("OpenAPIGenerator", () => { }); describe("createPostman", () => { - it("should generate a postman collection when a valid openAPI file is generated", function () { + it("should generate a postman collection when a valid OpenAPI file is generated", function () { const fsStub = sinon.stub(fs, "writeFileSync").returns(true); const succSpy = sinon.spy(logOutput.log, "success"); const errSpy = sinon.spy(logOutput.log, "error"); From 1b9a104bac11ff76f0f360441ea094fc7def13ed Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Sun, 13 Jul 2025 10:44:13 +0100 Subject: [PATCH 6/8] check whether we should try and convert an OpenAPI schema --- src/schemaHandler.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/schemaHandler.js b/src/schemaHandler.js index ccfb69d..71fc33e 100644 --- a/src/schemaHandler.js +++ b/src/schemaHandler.js @@ -15,8 +15,9 @@ class SchemaHandler { serverless.service?.provider?.apiGateway?.request?.schemas || {}; this.documentation = serverless.service.custom.documentation; this.openAPI = openAPI; + this.shouldConvert = true; - if (/(3\.1\.\d)/g(this.openAPI.openapi)) this.shouldConvert = false; + if (/(3\.1\.\d)/g.test(this.openAPI.openapi)) this.shouldConvert = false; this.modelReferences = {}; @@ -159,11 +160,11 @@ class SchemaHandler { } ); - this.logger.verbose( - `dereferenced model: ${JSON.stringify(dereferencedSchema)}` - ); - if (this.shouldConvert) { + this.logger.verbose( + `dereferenced model: ${JSON.stringify(dereferencedSchema)}` + ); + this.logger.verbose(`converting model: ${name}`); const convertedSchemas = SchemaConvertor.convert( dereferencedSchema, @@ -176,7 +177,13 @@ class SchemaHandler { return convertedSchemas; } - return dereferencedSchema; + this.logger.verbose( + `dereferenced model: ${JSON.stringify({ + schemas: { [name]: dereferencedSchema }, + })}` + ); + + return { schemas: { [name]: dereferencedSchema } }; } async __dereferenceSchema(schema) { From e1c0f69e6bea504a15754efb40a0da5a02943a6e Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Sun, 13 Jul 2025 10:45:35 +0100 Subject: [PATCH 7/8] update README with warning --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 86ab1b1..4f2bd24 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This will generate an OpenAPI V3 (up to v3.0.4) file for you from your serverless file. It can optionally generate a [Postman Collection V2](https://github.com/postmanlabs/openapi-to-postman) from the OpenAPI file for you too. This currently works for `http` and `httpApi` configurations. -If you are using the beta of 0.0.115, it will now try and create OpenAPI V3.1 (3.1.x) specs for you. Please see this [guide on migrating to V3.1](https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0) +If you are using the beta of 0.0.115, it will now try and create OpenAPI V3.1 (3.1.x) specs for you. Please see this [guide on migrating to V3.1](https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0). Whilst I perosnally use this plugin all the time, please do open and report bugs, and I will do my best to fix them. Originally based off of: https://github.com/temando/serverless-openapi-documentation From b2474e2df347eb8b525e91be5b972b5e9484419f Mon Sep 17 00:00:00 2001 From: Jared Evans Date: Sun, 13 Jul 2025 11:22:23 +0100 Subject: [PATCH 8/8] improve README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4f2bd24..ef7ab2b 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@

-This will generate an OpenAPI V3 (up to v3.0.4) file for you from your serverless file. It can optionally generate a [Postman Collection V2](https://github.com/postmanlabs/openapi-to-postman) from the OpenAPI file for you too. This currently works for `http` and `httpApi` configurations. +This will generate an [OpenAPI V3](https://spec.openapis.org/oas/v3.0.0.html) (up to v3.0.4) specification file for you from your serverless file. It can optionally generate a [Postman Collection V2](https://github.com/postmanlabs/openapi-to-postman) from the OpenAPI file for you too. This currently works for `http` and `httpApi` configurations. -If you are using the beta of 0.0.115, it will now try and create OpenAPI V3.1 (3.1.x) specs for you. Please see this [guide on migrating to V3.1](https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0). Whilst I perosnally use this plugin all the time, please do open and report bugs, and I will do my best to fix them. +If you are using the beta of 0.0.115, it will now try and create [OpenAPI V3.1 (3.1.x)](https://spec.openapis.org/oas/v3.1.0.html) specification file for you, should you run the command `serverless openapi generate -o openapi.json -f json -a 3.1.1 -p postman.json`. Please see this [guide on migrating to V3.1](https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0). Whilst I perosnally use this plugin all the time, please do open and report bugs, and I will do my best to fix them. Originally based off of: https://github.com/temando/serverless-openapi-documentation