Skip to content

Commit

Permalink
Merge pull request #702 from postmanlabs/release/v4.11.0
Browse files Browse the repository at this point in the history
Release/v4.11.0
  • Loading branch information
Dhwaneet Bhatt authored Apr 14, 2023
2 parents f94f06b + 708cd28 commit 0540979
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 28 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# OpenAPI-Postman Changelog

## [Unreleased]

## [v4.11.0] - 2021-04-14

### Added

- Fixed issue [#11680](https://github.com/postmanlabs/postman-app-support/issues/11680) Added support for contentType field for Formdata request bodies.
- Fixed issue [#10928](https://github.com/postmanlabs/postman-app-support/issues/10928) Added support for usage of interface version in CLI conversions with v2 as default.

### Fixed

- Fixed various known type errors related issues that were causing conversion errors.
- Fixed an issue where default response was not considered correctly while validating collection request response.

## Previous Releases
Newer releases follow the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format.

#### v4.10.2 (March 13, 2023)
* Fixed issue where Accept header was generated correctly in convertV2() interface.

Expand Down Expand Up @@ -436,3 +453,7 @@

#### v0.0.1 (October 23, 2018)
* Base release

[Unreleased]: https://github.com/postmanlabs/openapi-to-postman/compare/v4.11.0...HEAD

[v4.11.0]: https://github.com/postmanlabs/openapi-to-postman/compare/v4.10.2...v4.11.0
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,28 +56,31 @@ The converter can be used as a CLI tool as well. The following [command line opt

### Options

- `-s <source>`, `--spec <source>`
- `-s <source>`, `--spec <source>`
Used to specify the OpenAPI specification (file path) which is to be converted

- `-o <destination>`, `--output <destination>`
- `-o <destination>`, `--output <destination>`
Used to specify the destination file in which the collection is to be written

- `-p`, `--pretty`
- `-p`, `--pretty`
Used to pretty print the collection object while writing to a file

- `-O`, `--options`
- `-i`, `--interface-version`
Specifies the interface version of the converter to be used. Value can be 'v2' or 'v1'. Default is 'v2'.

- `-O`, `--options`
Used to supply options to the converter, for complete options details see [here](/OPTIONS.md)

- `-c`, `--options-config`
- `-c`, `--options-config`
Used to supply options to the converter through config file, for complete options details see [here](/OPTIONS.md)

- `-t`, `--test`
- `-t`, `--test`
Used to test the collection with an in-built sample specification

- `-v`, `--version`
- `-v`, `--version`
Specifies the version of the converter

- `-h`, `--help`
- `-h`, `--help`
Specifies all the options along with a few usage examples on the terminal


Expand Down
16 changes: 14 additions & 2 deletions bin/openapi2postmanv2.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var _ = require('lodash'),
definedOptions,
testFlag,
swaggerInput,
interfaceVersion,
swaggerData;

/**
Expand Down Expand Up @@ -41,6 +42,14 @@ function parseOptions (value) {
console.warn('\x1b[33m%s\x1b[0m', 'Warning: Invalid option supplied ', option[0]);
}
});

/**
* As v2 interface uses parametersResolution instead of previous requestParametersResolution option,
* override value of parametersResolution if it's not defined and requestParametersResolution is defined
*/
if (_.has(parsedOptions, 'requestParametersResolution') && !_.has(parsedOptions, 'parametersResolution')) {
parsedOptions.parametersResolution = parsedOptions.requestParametersResolution;
}
return parsedOptions;
}

Expand All @@ -50,6 +59,7 @@ program
.option('-o, --output <output>', 'Write the collection to an output file')
.option('-t, --test', 'Test the OPENAPI converter')
.option('-p, --pretty', 'Pretty print the JSON file')
.option('-i, --interface-version <interfaceVersion>', 'Interface version of convert() to be used')
.option('-c, --options-config <optionsConfig>', 'JSON file containing Converter options')
.option('-O, --options <options>', 'comma separated list of options', parseOptions);

Expand All @@ -76,6 +86,7 @@ inputFile = program.spec;
outputFile = program.output || false;
testFlag = program.test || false;
prettyPrintFlag = program.pretty || false;
interfaceVersion = program.interfaceVersion || 'v2';
configFile = program.optionsConfig || false;
definedOptions = (!(program.options instanceof Array) ? program.options : {});
swaggerInput;
Expand Down Expand Up @@ -112,7 +123,8 @@ function writetoFile(prettyPrintFlag, file, collection) {
* @returns {void}
*/
function convert(swaggerData) {
let options = {};
let options = {},
convertFn = interfaceVersion === 'v1' ? 'convert' : 'convertV2';

// apply options from config file if present
if (configFile) {
Expand All @@ -126,7 +138,7 @@ function convert(swaggerData) {
options = definedOptions;
}

Converter.convert({
Converter[convertFn]({
type: 'string',
data: swaggerData
}, options, (err, status) => {
Expand Down
14 changes: 11 additions & 3 deletions lib/schemaUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1513,7 +1513,7 @@ module.exports = {
var example,
exampleKey;

if (typeof exampleObj !== 'object') {
if (!exampleObj || typeof exampleObj !== 'object') {
return '';
}

Expand Down Expand Up @@ -1720,7 +1720,7 @@ module.exports = {

Object.keys(deepObject).forEach((key) => {
let value = deepObject[key];
if (typeof value === 'object') {
if (value && typeof value === 'object') {
extractedParams = _.concat(extractedParams, this.extractDeepObjectParams(value, objectKey + '[' + key + ']'));
}
else {
Expand Down Expand Up @@ -1896,6 +1896,7 @@ module.exports = {
updateOptions = {},
reqBody = new sdk.RequestBody(),
contentHeader,
contentTypes = {},
rDataMode,
params,
encoding,
Expand Down Expand Up @@ -2018,6 +2019,10 @@ module.exports = {
REQUEST_TYPE.ROOT, PARAMETER_SOURCE.REQUEST, components, options, schemaCache));
}
});

if (typeof _.get(encoding, `[${key}].contentType`) === 'string') {
contentTypes[key] = encoding[key].contentType;
}
}
// Collection v2.1 schema allows form param value to be only string
if (typeof value !== 'string') {
Expand Down Expand Up @@ -2055,6 +2060,9 @@ module.exports = {
});
}
param.description = description;
if (contentTypes[key]) {
param.contentType = contentTypes[key];
}
paramArray.push(param);
});
updateOptions = {
Expand Down Expand Up @@ -2640,7 +2648,7 @@ module.exports = {
// App / Collection transformer fail with the object syntax
if (item.request.url.variables.members && item.request.url.variables.members.length > 0) {
item.request.url.variables.members = _.map(item.request.url.variables.members, (m) => {
if (typeof m.description === 'object' && m.description.content) {
if (m.description && typeof m.description === 'object' && m.description.content) {
m.description = m.description.content;
}
return m;
Expand Down
50 changes: 42 additions & 8 deletions libV2/schemaUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,19 @@ let QUERYPARAM = 'query',
return { collectionVariables, pathVariables, baseUrl };
},

/**
* Provides ref stack limit for current instance
* @param {*} stackLimit - Defined stackLimit in options
*
* @returns {Number} Returns the stackLimit to be used
*/
getRefStackLimit = (stackLimit) => {
if (typeof stackLimit === 'number' && stackLimit > REF_STACK_LIMIT) {
return stackLimit;
}
return REF_STACK_LIMIT;
},

/**
* Resolve a given ref from the schema
* @param {Object} context - Global context object
Expand All @@ -246,9 +259,10 @@ let QUERYPARAM = 'query',
* @returns {Object} Returns the object that staisfies the schema
*/
resolveRefFromSchema = (context, $ref, stackDepth = 0, seenRef = {}) => {
const { specComponents } = context;
const { specComponents } = context,
{ stackLimit } = context.computedOptions;

if (stackDepth >= REF_STACK_LIMIT) {
if (stackDepth >= getRefStackLimit(stackLimit)) {
return { value: ERR_TOO_MANY_LEVELS };
}

Expand Down Expand Up @@ -315,9 +329,10 @@ let QUERYPARAM = 'query',
* @returns {Object} Returns the object that staisfies the schema
*/
resolveRefForExamples = (context, $ref, stackDepth = 0, seenRef = {}) => {
const { specComponents } = context;
const { specComponents } = context,
{ stackLimit } = context.computedOptions;

if (stackDepth >= REF_STACK_LIMIT) {
if (stackDepth >= getRefStackLimit(stackLimit)) {
return { value: ERR_TOO_MANY_LEVELS };
}

Expand Down Expand Up @@ -401,7 +416,7 @@ let QUERYPARAM = 'query',
let example = {},
exampleKey;

if (typeof exampleObj !== 'object') {
if (!exampleObj || typeof exampleObj !== 'object') {
return '';
}

Expand Down Expand Up @@ -467,12 +482,15 @@ let QUERYPARAM = 'query',
return new Error('Schema is empty');
}

if (stack >= REF_STACK_LIMIT) {
const { stackLimit } = context.computedOptions;

if (stack >= getRefStackLimit(stackLimit)) {
return { value: ERR_TOO_MANY_LEVELS };
}

stack++;

// eslint-disable-next-line one-var
const compositeKeyword = schema.anyOf ? 'anyOf' : 'oneOf',
{ concreteUtils } = context;

Expand Down Expand Up @@ -545,6 +563,11 @@ let QUERYPARAM = 'query',
{ includeDeprecated } = context.computedOptions;

_.forOwn(schema.properties, (property, propertyName) => {
// Skip property resolution if it's not schema object
if (!_.isObject(property)) {
return;
}

if (
property.format === 'decimal' ||
property.format === 'byte' ||
Expand Down Expand Up @@ -875,7 +898,7 @@ let QUERYPARAM = 'query',

Object.keys(deepObject).forEach((key) => {
let value = deepObject[key];
if (typeof value === 'object') {
if (value && typeof value === 'object') {
extractedParams = _.concat(extractedParams, extractDeepObjectParams(value, objectKey + '[' + key + ']'));
}
else {
Expand Down Expand Up @@ -1211,6 +1234,7 @@ let QUERYPARAM = 'query',
resolveFormDataRequestBodyForPostmanRequest = (context, requestBodyContent) => {
let bodyData = '',
formDataParams = [],
encoding = {},
requestBodyData = {
mode: 'formdata',
formdata: formDataParams
Expand All @@ -1221,9 +1245,11 @@ let QUERYPARAM = 'query',
}

bodyData = resolveRequestBodyData(context, requestBodyContent.schema);
encoding = _.get(requestBodyContent, 'encoding', {});

_.forOwn(bodyData, (value, key) => {
let requestBodySchema,
contentType = null,
paramSchema,
description,
param;
Expand All @@ -1240,6 +1266,10 @@ let QUERYPARAM = 'query',
_.indexOf(requestBodySchema.required, key) !== -1;
description = getParameterDescription(paramSchema);

if (typeof _.get(encoding, `[${key}].contentType`) === 'string') {
contentType = encoding[key].contentType;
}

// TODO: Add handling for headers from encoding

if (paramSchema && paramSchema.type === 'binary') {
Expand All @@ -1258,6 +1288,9 @@ let QUERYPARAM = 'query',
}

param.description = description;
if (contentType) {
param.contentType = contentType;
}

formDataParams.push(param);
});
Expand Down Expand Up @@ -1720,8 +1753,9 @@ let QUERYPARAM = 'query',
let responses = [],
requestAcceptHeader;

_.forOwn(operationItem.responses, (responseSchema, code) => {
_.forOwn(operationItem.responses, (responseObj, code) => {
let response,
responseSchema = _.has(responseObj, '$ref') ? resolveSchema(context, responseObj) : responseObj,
{ includeAuthInfoInExample } = context.computedOptions,
responseAuthHelper,
auth = request.auth,
Expand Down
6 changes: 4 additions & 2 deletions libV2/validationUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ function extractDeepObjectParams (deepObject, objectKey) {

Object.keys(deepObject).forEach((key) => {
let value = deepObject[key];
if (typeof value === 'object') {
if (value && typeof value === 'object') {
extractedParams = _.concat(extractedParams, extractDeepObjectParams(value, objectKey + '[' + key + ']'));
}
else {
Expand Down Expand Up @@ -2371,7 +2371,7 @@ function checkResponses (context, transaction, transactionPathPrefix, schemaPath
// for each response, find the appropriate response from schemaPath, and then validate response body and headers
async.map(responses, (response, responseCallback) => {
let thisResponseCode = _.toString(response.code),
thisSchemaResponse = _.get(schemaPath, ['responses', thisResponseCode]),
thisSchemaResponse = _.get(schemaPath, ['responses', thisResponseCode], _.get(schemaPath, 'responses.default')),
responsePathPrefix = thisResponseCode;

// X can be used as wild card character, so response code like 2XX in definition are valid
Expand Down Expand Up @@ -2449,6 +2449,8 @@ function checkResponses (context, transaction, transactionPathPrefix, schemaPath
missingResponses = [];

_.each(_.get(schemaPath, 'responses'), (responseObj, responseCode) => {
responseCode = responseCode === 'default' ? '500' : responseCode;

if (!_.includes(matchedResponses, responseCode)) {
let mismatchObj = {
property: 'RESPONSE',
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "openapi-to-postmanv2",
"version": "4.10.2",
"version": "4.11.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",
Expand Down
8 changes: 8 additions & 0 deletions test/data/valid_openapi/required_in_parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@
"type": "string"
}
}
},
"encoding": {
"formParam1": {
"contentType": "application/xml"
},
"formParam2": {
"contentType": "application/js"
}
}
}
}
Expand Down
Loading

0 comments on commit 0540979

Please sign in to comment.