From c12e7387a899286c5cb03f34e35a59b1746f2ba4 Mon Sep 17 00:00:00 2001 From: Vishal Shingala Date: Tue, 14 May 2024 19:03:12 +0530 Subject: [PATCH 1/6] Added simplified request and response body matching in case of multiple examples --- libV2/schemaUtils.js | 103 +++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 43 deletions(-) diff --git a/libV2/schemaUtils.js b/libV2/schemaUtils.js index 3fbf47ab..dfea3e7d 100644 --- a/libV2/schemaUtils.js +++ b/libV2/schemaUtils.js @@ -1092,7 +1092,52 @@ let QUERYPARAM = 'query', * @returns {Array} Examples for corresponding operation */ generateExamples = (context, responseExamples, requestBodyExamples, responseBodySchema, isXMLExample) => { - const pmExamples = []; + const pmExamples = [], + responseExampleKeys = _.map(responseExamples, 'key'), + requestBodyExampleKeys = _.map(requestBodyExamples, 'key'), + matchedKeys = _.intersectionBy(responseExampleKeys, requestBodyExampleKeys, _.toLower), + usedRequestExamples = _.fill(Array(requestBodyExamples.length), false), + exampleKeyComparator = (example, key) => { + return _.toLower(example.key) === _.toLower(key); + }; + + /** + * To generate examples, we first try to do matching of request and response examples based on example keys, + * If there is any matching found, we'll create example from it and ignore non-matching keys + */ + if (matchedKeys.length) { + _.forEach(matchedKeys, (key) => { + const matchedRequestExamples = _.filter(requestBodyExamples, (example) => { + return exampleKeyComparator(example, key); + }), + responseExample = _.find(responseExamples, (example) => { + return exampleKeyComparator(example, key); + }); + + let requestExample = _.find(matchedRequestExamples, ['contentType', _.get(responseExample, 'contentType')]), + responseExampleData; + + if (!requestExample) { + requestExample = _.head(matchedRequestExamples); + } + + responseExampleData = getExampleData(context, { [responseExample.key]: responseExample.value }); + + if (isXMLExample) { + responseExampleData = getXMLExampleData(context, responseExampleData, responseBodySchema); + } + + pmExamples.push({ + request: getExampleData(context, { [requestExample.key]: requestExample.value }), + response: responseExampleData, + name: _.get(responseExample, 'value.summary') || + (responseExample.key !== '_default' && responseExample.key) || + _.get(requestExample, 'value.summary') || requestExample.key || 'Example' + }); + }); + + return pmExamples; + } _.forEach(responseExamples, (responseExample, index) => { @@ -1101,13 +1146,19 @@ let QUERYPARAM = 'query', } let responseExampleData = getExampleData(context, { [responseExample.key]: responseExample.value }), - requestExample; + requestExample, + matchedRequestBodyExamples = _.filter(requestBodyExamples, ['contentType', responseExample.contentType]); + + // If content-types are not matching, match with any present content-types + if (_.isEmpty(matchedRequestBodyExamples)) { + matchedRequestBodyExamples = requestBodyExamples; + } if (isXMLExample) { responseExampleData = getXMLExampleData(context, responseExampleData, responseBodySchema); } - if (_.isEmpty(requestBodyExamples)) { + if (_.isEmpty(matchedRequestBodyExamples)) { pmExamples.push({ response: responseExampleData, name: _.get(responseExample, 'value.summary') || responseExample.key @@ -1115,46 +1166,12 @@ let QUERYPARAM = 'query', return; } - requestExample = _.find(requestBodyExamples, (example, index) => { - if ( - example.contentType === responseExample.contentType && - _.toLower(example.key) === _.toLower(responseExample.key) - ) { - requestBodyExamples[index].isUsed = true; - return true; - } - return false; - }); - - // If exact content type is not matching, pick first content type with same example key - if (!requestExample) { - requestExample = _.find(requestBodyExamples, (example, index) => { - if (_.toLower(example.key) === _.toLower(responseExample.key)) { - requestBodyExamples[index].isUsed = true; - return true; - } - return false; - }); + if (requestBodyExamples[index] && !usedRequestExamples[index]) { + requestExample = requestBodyExamples[index]; + usedRequestExamples[index] = true; } - - if (!requestExample) { - if (requestBodyExamples[index] && !requestBodyExamples[index].isUsed) { - requestExample = requestBodyExamples[index]; - requestBodyExamples[index].isUsed = true; - } - else { - for (let i = 0; i < requestBodyExamples.length; i++) { - if (!requestBodyExamples[i].isUsed) { - requestExample = requestBodyExamples[i]; - requestBodyExamples[i].isUsed = true; - break; - } - } - - if (!requestExample) { - requestExample = requestBodyExamples[0]; - } - } + else { + requestExample = requestBodyExamples[0]; } pmExamples.push({ @@ -1170,7 +1187,7 @@ let QUERYPARAM = 'query', for (let i = 0; i < requestBodyExamples.length; i++) { - if (!requestBodyExamples[i].isUsed || pmExamples.length === 0) { + if (!usedRequestExamples[i] || pmExamples.length === 0) { if (!responseExample) { responseExample = _.head(responseExamples); From 87cf696720991bf2353e877878b80eea98dc468e Mon Sep 17 00:00:00 2001 From: Vishal Shingala Date: Tue, 14 May 2024 19:10:42 +0530 Subject: [PATCH 2/6] Added comments for req-res matching for multi examples --- libV2/schemaUtils.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/libV2/schemaUtils.js b/libV2/schemaUtils.js index dfea3e7d..b9dee5ad 100644 --- a/libV2/schemaUtils.js +++ b/libV2/schemaUtils.js @@ -1082,7 +1082,16 @@ let QUERYPARAM = 'query', /** * Generates postman equivalent examples which contains request and response mappings of - * each example based on examples mentioned ind definition + * each example based on examples mentioned in definition + * + * This matching between request bodies and response bodies are done in following order. + * 1. Try matching keys from request and response examples + * 2. If any key matching is found, we'll generate example from it and ignore non-matching keys + * 3. If no matching key is found, we'll generate examples based on positional matching. + * + * Positional matching means first example in request body will be matched with first example + * in response body and so on. Any left over request or response body for which + * positional matching is not found, we'll use first req/res example. * * @param {Object} context - Global context object * @param {Object} responseExamples - Examples defined in the response @@ -1101,10 +1110,7 @@ let QUERYPARAM = 'query', return _.toLower(example.key) === _.toLower(key); }; - /** - * To generate examples, we first try to do matching of request and response examples based on example keys, - * If there is any matching found, we'll create example from it and ignore non-matching keys - */ + // Do keys matching first and ignore any leftover req/res body for which matching is not found if (matchedKeys.length) { _.forEach(matchedKeys, (key) => { const matchedRequestExamples = _.filter(requestBodyExamples, (example) => { @@ -1139,6 +1145,7 @@ let QUERYPARAM = 'query', return pmExamples; } + // No key matching between req and res were found, so perform positional matching now _.forEach(responseExamples, (responseExample, index) => { if (!_.isObject(responseExample)) { @@ -1185,6 +1192,7 @@ let QUERYPARAM = 'query', let responseExample, responseExampleData; + // Add any left over request body examples with first response body as matching for (let i = 0; i < requestBodyExamples.length; i++) { if (!usedRequestExamples[i] || pmExamples.length === 0) { From 4d94c7e9643a709a2ec6241127702e721732087a Mon Sep 17 00:00:00 2001 From: Vishal Shingala Date: Wed, 15 May 2024 01:10:19 +0530 Subject: [PATCH 3/6] Added tests for updated multi example support --- .../multiContentTypesMultiExample.json | 127 +++++++++++++ .../multiExampleMatchingRequestResponse.yaml | 8 + .../multiExampleRequestVariousResponse.yaml | 106 +++++++++++ test/unit/convertV2.test.js | 173 ++++++++++++++---- 4 files changed, 379 insertions(+), 35 deletions(-) create mode 100644 test/data/valid_openapi/multiContentTypesMultiExample.json create mode 100644 test/data/valid_openapi/multiExampleRequestVariousResponse.yaml diff --git a/test/data/valid_openapi/multiContentTypesMultiExample.json b/test/data/valid_openapi/multiContentTypesMultiExample.json new file mode 100644 index 00000000..638aea32 --- /dev/null +++ b/test/data/valid_openapi/multiContentTypesMultiExample.json @@ -0,0 +1,127 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "Swagger Petstore", + "license": { + "name": "MIT" + } + }, + "servers": [{ + "url": "http://petstore.swagger.io/v1" + }], + "paths": { + "/pets": { + "post": { + "summary": "List all pets", + "operationId": "pets - updated", + "tags": [ + "pets" + ], + "parameters": [{ + "name": "limit1", + "in": "query", + "description": "How many items to return at one time (max 100)", + "schema": { + "type": "integer", + "format": "int32" + } + }], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "ok_example": { + "value": { + "message": "ok" + } + }, + "not_ok_example": { + "value": { + "message": "fail" + } + } + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "ok_example": { + "value": { + "message": "ok" + } + }, + "not_ok_example": { + "value": { + "message": "fail" + } + } + } + } + } + }, + "responses": { + "default": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "example": { + "message": "Not Found" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "example": { + "message": "Not Found" + } + } + } + }, + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "example": { + "message": "Found", + "code": 200123 + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Error": { + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + } + } + } +} diff --git a/test/data/valid_openapi/multiExampleMatchingRequestResponse.yaml b/test/data/valid_openapi/multiExampleMatchingRequestResponse.yaml index 050a9347..ea5a1d74 100644 --- a/test/data/valid_openapi/multiExampleMatchingRequestResponse.yaml +++ b/test/data/valid_openapi/multiExampleMatchingRequestResponse.yaml @@ -22,6 +22,10 @@ paths: value: includedFields: - user + extra-value: + value: + includedFields: + - eyeColor responses: 200: description: None @@ -44,6 +48,10 @@ paths: { "user": 1 } + extra-value-2: + value: + includedFields: + - eyeColor components: schemas: World: diff --git a/test/data/valid_openapi/multiExampleRequestVariousResponse.yaml b/test/data/valid_openapi/multiExampleRequestVariousResponse.yaml new file mode 100644 index 00000000..7910b60e --- /dev/null +++ b/test/data/valid_openapi/multiExampleRequestVariousResponse.yaml @@ -0,0 +1,106 @@ +openapi: 3.0.0 +info: + title: None + version: 1.0.0 + description: None +paths: + /v1: + post: + requestBody: + content: + 'application/json': + schema: + $ref: "#/components/schemas/World" + examples: + valid-request: + value: + includedFields: + - user + - height + - weight + missing-required-parameter: + value: + includedFields: + - eyeColor + responses: + 200: + description: None + content: + 'application/json': + schema: + $ref: "#/components/schemas/Request" + examples: + valid-request: + summary: Request with only required params + value: + { + "user": 1 + } + not-matching-key: + summary: Complete request + value: + { + "user": 99, + "height": 168, + "weight": 44 + } + 400: + description: None + content: + 'application/json': + schema: + $ref: "#/components/schemas/Request" + examples: + missing-required-parameter: + summary: Request with only bad params + value: + { + "eyeColor": "gray" + } + 500: + description: None + content: + 'application/json': + schema: + $ref: "#/components/schemas/Request" + examples: + not-matching-key-1: + summary: Failed request - Negative user + value: + { + "user": -99 + } + not-matching-key-2: + summary: Failed request - All negatives + value: + { + "user": -999, + "height": -168, + "weight": -44 + } + +components: + schemas: + World: + type: object + properties: + includedFields: + type: array + Request: + type: object + required: + - user + - height + - weight + properties: + user: + type: integer + description: None + height: + type: integer + description: None + weight: + type: integer + description: None + eyeColor: + type: string diff --git a/test/unit/convertV2.test.js b/test/unit/convertV2.test.js index 41852bb1..44aad990 100644 --- a/test/unit/convertV2.test.js +++ b/test/unit/convertV2.test.js @@ -102,7 +102,11 @@ const expect = require('chai').expect, multiExampleRequestResponse = path.join(__dirname, VALID_OPENAPI_PATH, '/multiExampleRequestResponse.yaml'), multiExampleMatchingRequestResponse = - path.join(__dirname, VALID_OPENAPI_PATH, '/multiExampleMatchingRequestResponse.yaml'); + path.join(__dirname, VALID_OPENAPI_PATH, '/multiExampleMatchingRequestResponse.yaml'), + multiContentTypesMultiExample = + path.join(__dirname, VALID_OPENAPI_PATH, '/multiContentTypesMultiExample.json'), + multiExampleRequestVariousResponse = + path.join(__dirname, VALID_OPENAPI_PATH, '/multiExampleRequestVariousResponse.yaml'); describe('The convert v2 Function', function() { @@ -2544,44 +2548,50 @@ describe('The convert v2 Function', function() { }); }); - it('both request and response body contains multiple examples with matching keys', function(done) { - var openapi = fs.readFileSync(multiExampleMatchingRequestResponse, 'utf8'); - Converter.convertV2({ type: 'string', data: openapi }, { parametersResolution: 'Example' }, - (err, conversionResult) => { - expect(err).to.be.null; - expect(conversionResult.result).to.equal(true); - expect(conversionResult.output.length).to.equal(1); - expect(conversionResult.output[0].type).to.equal('collection'); - expect(conversionResult.output[0].data).to.have.property('info'); - expect(conversionResult.output[0].data).to.have.property('item'); - expect(conversionResult.output[0].data.item[0].item.length).to.equal(1); + it('both request and response body contains multiple examples with matching keys and ignore non matching keys', + function(done) { + const openapi = fs.readFileSync(multiExampleMatchingRequestResponse, 'utf8'); + Converter.convertV2({ type: 'string', data: openapi }, { parametersResolution: 'Example' }, + (err, conversionResult) => { + expect(err).to.be.null; + expect(conversionResult.result).to.equal(true); + expect(conversionResult.output.length).to.equal(1); + expect(conversionResult.output[0].type).to.equal('collection'); + expect(conversionResult.output[0].data).to.have.property('info'); + expect(conversionResult.output[0].data).to.have.property('item'); + expect(conversionResult.output[0].data.item[0].item.length).to.equal(1); - const item = conversionResult.output[0].data.item[0].item[0]; + const item = conversionResult.output[0].data.item[0].item[0]; - expect(JSON.parse(item.request.body.raw)).to.eql({ - includedFields: ['user', 'height', 'weight'] - }); - expect(item.response).to.have.lengthOf(2); - expect(item.response[0].name).to.eql('Complete request'); - expect(item.response[0]._postman_previewlanguage).to.eql('json'); - expect(JSON.parse(item.response[0].body)).to.eql({ - user: 1, - height: 168, - weight: 44 - }); - expect(JSON.parse(item.response[0].originalRequest.body.raw)).to.eql({ - includedFields: ['user', 'height', 'weight'] - }); + expect(JSON.parse(item.request.body.raw)).to.eql({ + includedFields: ['user', 'height', 'weight'] + }); - expect(item.response[1].name).to.eql('Request with only required params'); - expect(item.response[1]._postman_previewlanguage).to.eql('json'); - expect(JSON.parse(item.response[1].body)).to.eql({ user: 1 }); - expect(JSON.parse(item.response[1].originalRequest.body.raw)).to.eql({ - includedFields: ['user'] + /** + * Even though both req and res has 3 examples, only 2 example should be present + * as only 2 examples have matching keys + */ + expect(item.response).to.have.lengthOf(2); + expect(item.response[0].name).to.eql('Complete request'); + expect(item.response[0]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[0].body)).to.eql({ + user: 1, + height: 168, + weight: 44 + }); + expect(JSON.parse(item.response[0].originalRequest.body.raw)).to.eql({ + includedFields: ['user', 'height', 'weight'] + }); + + expect(item.response[1].name).to.eql('Request with only required params'); + expect(item.response[1]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[1].body)).to.eql({ user: 1 }); + expect(JSON.parse(item.response[1].originalRequest.body.raw)).to.eql({ + includedFields: ['user'] + }); + done(); }); - done(); - }); - }); + }); it('both request and response body contains multiple examples in mentioned order when no matching keys', function(done) { @@ -2624,5 +2634,98 @@ describe('The convert v2 Function', function() { done(); }); }); + + it('request body and responses contain multiple content types and multiple examples', function(done) { + const openapi = fs.readFileSync(multiContentTypesMultiExample, 'utf8'); + Converter.convertV2({ type: 'string', data: openapi }, { parametersResolution: 'Example' }, + (err, conversionResult) => { + expect(err).to.be.null; + expect(conversionResult.result).to.equal(true); + expect(conversionResult.output.length).to.equal(1); + expect(conversionResult.output[0].type).to.equal('collection'); + expect(conversionResult.output[0].data).to.have.property('info'); + expect(conversionResult.output[0].data).to.have.property('item'); + expect(conversionResult.output[0].data.item[0].item.length).to.equal(1); + + const item = conversionResult.output[0].data.item[0].item[0], + okReqExample = { message: 'ok' }, + failReqExample = { message: 'fail' }, + okResExample = { message: 'Found', code: 200123 }, + failResExample = { message: 'Not Found' }; + + expect(JSON.parse(item.request.body.raw)).to.eql(okReqExample); + expect(item.response).to.have.lengthOf(4); + expect(item.response[0].name).to.eql('ok_example'); + expect(item.response[0].code).to.eql(200); + expect(item.response[0]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[0].originalRequest.body.raw)).to.eql(okReqExample); + expect(JSON.parse(item.response[0].body)).to.eql(okResExample); + + expect(item.response[1].name).to.eql('not_ok_example'); + expect(item.response[1].code).to.eql(200); + expect(item.response[1]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[1].originalRequest.body.raw)).to.eql(failReqExample); + expect(JSON.parse(item.response[1].body)).to.eql(okResExample); + + expect(item.response[2].name).to.eql('ok_example'); + expect(item.response[2].code).to.eql(500); + expect(item.response[2]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[2].originalRequest.body.raw)).to.eql(okReqExample); + expect(JSON.parse(item.response[2].body)).to.eql(failResExample); + + expect(item.response[3].name).to.eql('not_ok_example'); + expect(item.response[3].code).to.eql(500); + expect(item.response[3]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[3].originalRequest.body.raw)).to.eql(failReqExample); + expect(JSON.parse(item.response[3].body)).to.eql(failResExample); + done(); + }); + }); + + it('request body and responses contain multiple examples with various response code ' + + 'having single or multiple examples', function(done) { + const openapi = fs.readFileSync(multiExampleRequestVariousResponse, 'utf8'); + Converter.convertV2({ type: 'string', data: openapi }, { parametersResolution: 'Example' }, + (err, conversionResult) => { + expect(err).to.be.null; + expect(conversionResult.result).to.equal(true); + expect(conversionResult.output.length).to.equal(1); + expect(conversionResult.output[0].type).to.equal('collection'); + expect(conversionResult.output[0].data).to.have.property('info'); + expect(conversionResult.output[0].data).to.have.property('item'); + expect(conversionResult.output[0].data.item[0].item.length).to.equal(1); + + const item = conversionResult.output[0].data.item[0].item[0], + reqBody1 = { includedFields: ['user', 'height', 'weight'] }, + reqBody2 = { includedFields: ['eyeColor'] }; + + expect(JSON.parse(item.request.body.raw)).to.eql(reqBody1); + expect(item.response).to.have.lengthOf(4); + expect(item.response[0].name).to.eql('Request with only required params'); + expect(item.response[0].code).to.eql(200); + expect(item.response[0]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[0].originalRequest.body.raw)).to.eql(reqBody1); + expect(JSON.parse(item.response[0].body)).to.eql({ user: 1 }); + + expect(item.response[1].name).to.eql('Request with only bad params'); + expect(item.response[1].code).to.eql(400); + expect(item.response[1]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[1].originalRequest.body.raw)).to.eql(reqBody2); + expect(JSON.parse(item.response[1].body)).to.eql({ eyeColor: 'gray' }); + + expect(item.response[2].name).to.eql('Failed request - Negative user'); + expect(item.response[2].code).to.eql(500); + expect(item.response[2]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[2].originalRequest.body.raw)).to.eql(reqBody1); + expect(JSON.parse(item.response[2].body)).to.eql({ user: -99 }); + + expect(item.response[3].name).to.eql('Failed request - All negatives'); + expect(item.response[3].code).to.eql(500); + expect(item.response[3]._postman_previewlanguage).to.eql('json'); + expect(JSON.parse(item.response[3].originalRequest.body.raw)).to.eql(reqBody2); + expect(JSON.parse(item.response[3].body)).to.eql({ user: -999, height: -168, weight: -44 }); + done(); + }); + }); }); }); From eb3cc5e14a59bed7b7488eaa52a1a44963812693 Mon Sep 17 00:00:00 2001 From: Vishal Shingala Date: Wed, 15 May 2024 01:11:02 +0530 Subject: [PATCH 4/6] Use only correct content type request body examples to generate collection examples --- libV2/schemaUtils.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/libV2/schemaUtils.js b/libV2/schemaUtils.js index b9dee5ad..e0d62b7c 100644 --- a/libV2/schemaUtils.js +++ b/libV2/schemaUtils.js @@ -1153,19 +1153,13 @@ let QUERYPARAM = 'query', } let responseExampleData = getExampleData(context, { [responseExample.key]: responseExample.value }), - requestExample, - matchedRequestBodyExamples = _.filter(requestBodyExamples, ['contentType', responseExample.contentType]); - - // If content-types are not matching, match with any present content-types - if (_.isEmpty(matchedRequestBodyExamples)) { - matchedRequestBodyExamples = requestBodyExamples; - } + requestExample; if (isXMLExample) { responseExampleData = getXMLExampleData(context, responseExampleData, responseBodySchema); } - if (_.isEmpty(matchedRequestBodyExamples)) { + if (_.isEmpty(requestBodyExamples)) { pmExamples.push({ response: responseExampleData, name: _.get(responseExample, 'value.summary') || responseExample.key @@ -1384,7 +1378,15 @@ let QUERYPARAM = 'query', }; }); } - return generateExamples(context, responseExamples, requestBodyExamples, requestBodySchema, isBodyTypeXML); + + let matchedRequestBodyExamples = _.filter(requestBodyExamples, ['contentType', bodyType]); + + // If content-types are not matching, match with any present content-types + if (_.isEmpty(matchedRequestBodyExamples)) { + matchedRequestBodyExamples = requestBodyExamples; + } + + return generateExamples(context, responseExamples, matchedRequestBodyExamples, requestBodySchema, isBodyTypeXML); } return [{ [bodyKey]: bodyData }]; From 799d3c730afd7100417a21f6a20207459f557338 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 17 May 2024 11:05:33 +0000 Subject: [PATCH 5/6] Prepare release v4.21.0 --- CHANGELOG.md | 6 +++++- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2edfa55..640dee19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [v4.21.0] - 2024-05-17 + ## [v4.20.1] - 2024-03-27 ### Fixed @@ -614,7 +616,9 @@ Newer releases follow the [Keep a Changelog](https://keepachangelog.com/en/1.0.0 - Base release -[Unreleased]: https://github.com/postmanlabs/openapi-to-postman/compare/v4.20.1...HEAD +[Unreleased]: https://github.com/postmanlabs/openapi-to-postman/compare/v4.21.0...HEAD + +[v4.21.0]: https://github.com/postmanlabs/openapi-to-postman/compare/v4.20.1...v4.21.0 [v4.20.1]: https://github.com/postmanlabs/openapi-to-postman/compare/v4.20.0...v4.20.1 diff --git a/package-lock.json b/package-lock.json index 9bc695f0..4489d797 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openapi-to-postmanv2", - "version": "4.20.1", + "version": "4.21.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "openapi-to-postmanv2", - "version": "4.20.1", + "version": "4.21.0", "license": "Apache-2.0", "dependencies": { "ajv": "8.11.0", diff --git a/package.json b/package.json index 1e29f3c4..f326089c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openapi-to-postmanv2", - "version": "4.20.1", + "version": "4.21.0", "description": "Convert a given OpenAPI specification to Postman Collection v2.0", "homepage": "https://github.com/postmanlabs/openapi-to-postman", "bugs": "https://github.com/postmanlabs/openapi-to-postman/issues", From a2c3651d99471da161f8511399c4e82704113412 Mon Sep 17 00:00:00 2001 From: Vishal Shingala Date: Fri, 17 May 2024 16:37:27 +0530 Subject: [PATCH 6/6] Added changelogs --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 640dee19..c5859324 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ## [v4.21.0] - 2024-05-17 +### Added + +- Added support for simplified request and response body matching in case of multiple examples. + ## [v4.20.1] - 2024-03-27 ### Fixed