Skip to content

Commit fec6268

Browse files
authored
Merge pull request #803 from thim81/develop-801-request-contenttype-body
Conversion - Added option to set preferred request body content-type
2 parents 930197a + b883271 commit fec6268

File tree

5 files changed

+266
-21
lines changed

5 files changed

+266
-21
lines changed

OPTIONS.md

+6
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ collapseFolders|boolean|-|true|Importing will collapse all folders that have onl
66
optimizeConversion|boolean|-|true|Optimizes conversion for large specification, disabling this option might affect the performance of conversion.|CONVERSION|v1
77
requestParametersResolution|enum|Example, Schema|Schema|Select whether to generate the request parameters based on the [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject) in the schema.|CONVERSION|v1
88
exampleParametersResolution|enum|Example, Schema|Example|Select whether to generate the response parameters based on the [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject) in the schema.|CONVERSION|v1
9+
disabledParametersValidation|boolean|-|true|Whether disabled parameters of collection should be validated|VALIDATION|v2, v1
910
parametersResolution|enum|Example, Schema|Schema|Select whether to generate the request and response parameters based on the [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject) in the schema.|CONVERSION|v2, v1
1011
folderStrategy|enum|Paths, Tags|Paths|Select whether to create folders according to the spec’s paths or tags.|CONVERSION|v2, v1
12+
schemaFaker|boolean|-|true|Whether or not schemas should be faked.|CONVERSION|v2, v1
13+
stackLimit|integer|-|10|Number of nesting limit till which schema resolution will happen. Increasing this limit may result in more time to convert collection depending on complexity of specification. (To make sure this option works correctly "optimizeConversion" option needs to be disabled)|CONVERSION|v2, v1
1114
includeAuthInfoInExample|boolean|-|true|Select whether to include authentication parameters in the example request.|CONVERSION|v2, v1
1215
shortValidationErrors|boolean|-|false|Whether detailed error messages are required for request <> schema validation operations.|VALIDATION|v2, v1
1316
validationPropertiesToIgnore|array|-|[]|Specific properties (parts of a request/response pair) to ignore during validation. Must be sent as an array of strings. Valid inputs in the array: PATHVARIABLE, QUERYPARAM, HEADER, BODY, RESPONSE_HEADER, RESPONSE_BODY|VALIDATION|v2, v1
@@ -20,5 +23,8 @@ strictRequestMatching|boolean|-|false|Whether requests should be strictly matche
2023
allowUrlPathVarMatching|boolean|-|false|Whether to allow matching path variables that are available as part of URL itself in the collection request|VALIDATION|v2, v1
2124
enableOptionalParameters|boolean|-|true|Optional parameters aren't selected in the collection. Once enabled they will be selected in the collection and request as well.|CONVERSION|v2, v1
2225
keepImplicitHeaders|boolean|-|false|Whether to keep implicit headers from the OpenAPI specification, which are removed by default.|CONVERSION|v2, v1
26+
includeWebhooks|boolean|-|false|Select whether to include Webhooks in the generated collection|CONVERSION|v2, v1
27+
includeReferenceMap|boolean|-|false|Whether or not to include reference map or not as part of output|BUNDLE|v2, v1
2328
includeDeprecated|boolean|-|true|Select whether to include deprecated operations, parameters, and properties in generated collection or not|CONVERSION, VALIDATION|v2, v1
2429
alwaysInheritAuthentication|boolean|-|false|Whether authentication details should be included on every request, or always inherited from the collection.|CONVERSION|v2, v1
30+
preferredRequestBodyType|enum|x-www-form-urlencoded, form-data, raw, first-listed|first-listed|When there are multiple content-types defined in the request body of OpenAPI, the conversion selects the preferred option content-type as request body.If "first-listed" is set, the first content-type defined in the OpenAPI spec will be selected.|CONVERSION|v2

lib/options.js

+14
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,20 @@ module.exports = {
388388
usage: ['CONVERSION'],
389389
supportedIn: [VERSION20, VERSION30, VERSION31],
390390
supportedModuleVersion: [MODULE_VERSION.V2, MODULE_VERSION.V1]
391+
},
392+
{
393+
name: 'Select request body type',
394+
id: 'preferredRequestBodyType',
395+
type: 'enum',
396+
default: 'first-listed',
397+
availableOptions: ['x-www-form-urlencoded', 'form-data', 'raw', 'first-listed'],
398+
description: 'When there are multiple content-types defined in the request body of OpenAPI, the conversion ' +
399+
'selects the preferred option content-type as request body.If "first-listed" is set, the first ' +
400+
'content-type defined in the OpenAPI spec will be selected.',
401+
external: false,
402+
usage: ['CONVERSION'],
403+
supportedIn: [VERSION20, VERSION30, VERSION31],
404+
supportedModuleVersion: [MODULE_VERSION.V2]
391405
}
392406
];
393407

libV2/schemaUtils.js

+36-6
Original file line numberDiff line numberDiff line change
@@ -1640,7 +1640,13 @@ let QUERYPARAM = 'query',
16401640

16411641
resolveRequestBodyForPostmanRequest = (context, operationItem) => {
16421642
let requestBody = operationItem.requestBody,
1643-
requestContent;
1643+
requestContent,
1644+
encodedRequestBody,
1645+
formDataRequestBody,
1646+
rawModeRequestBody;
1647+
1648+
const { preferredRequestBodyType: optionRequestBodyType } = context.computedOptions,
1649+
preferredRequestBodyType = optionRequestBodyType || 'first-listed';
16441650

16451651
if (!requestBody) {
16461652
return requestBody;
@@ -1659,15 +1665,38 @@ let QUERYPARAM = 'query',
16591665
};
16601666
}
16611667

1662-
if (requestContent[URLENCODED]) {
1663-
return resolveUrlEncodedRequestBodyForPostmanRequest(context, requestContent[URLENCODED]);
1668+
for (const contentType in requestContent) {
1669+
if (contentType === URLENCODED) {
1670+
encodedRequestBody = resolveUrlEncodedRequestBodyForPostmanRequest(context, requestContent[contentType]);
1671+
if (preferredRequestBodyType === 'first-listed') {
1672+
return encodedRequestBody;
1673+
}
1674+
}
1675+
else if (contentType === FORM_DATA) {
1676+
formDataRequestBody = resolveFormDataRequestBodyForPostmanRequest(context, requestContent[contentType]);
1677+
if (preferredRequestBodyType === 'first-listed') {
1678+
return formDataRequestBody;
1679+
}
1680+
}
1681+
else {
1682+
rawModeRequestBody = resolveRawModeRequestBodyForPostmanRequest(context, requestContent);
1683+
if (preferredRequestBodyType === 'first-listed') {
1684+
return rawModeRequestBody;
1685+
}
1686+
}
16641687
}
16651688

1666-
if (requestContent[FORM_DATA]) {
1667-
return resolveFormDataRequestBodyForPostmanRequest(context, requestContent[FORM_DATA]);
1689+
// Check if preferredRequestBodyType is provided and return the corresponding request body if available
1690+
if (preferredRequestBodyType) {
1691+
if (preferredRequestBodyType === 'x-www-form-urlencoded' && encodedRequestBody) {
1692+
return encodedRequestBody;
1693+
}
1694+
else if (preferredRequestBodyType === 'form-data' && formDataRequestBody) {
1695+
return formDataRequestBody;
1696+
}
16681697
}
16691698

1670-
return resolveRawModeRequestBodyForPostmanRequest(context, requestContent);
1699+
return rawModeRequestBody;
16711700
},
16721701

16731702
resolvePathItemParams = (context, operationParam, pathParam) => {
@@ -2236,6 +2265,7 @@ module.exports = {
22362265
},
22372266

22382267
resolveResponseForPostmanRequest,
2268+
resolveRequestBodyForPostmanRequest,
22392269
resolveRefFromSchema,
22402270
resolveSchema
22412271
};

test/system/structure.test.js

+26-15
Original file line numberDiff line numberDiff line change
@@ -30,35 +30,36 @@ const optionIds = [
3030
'includeDeprecated',
3131
'parametersResolution',
3232
'disabledParametersValidation',
33-
'alwaysInheritAuthentication'
33+
'alwaysInheritAuthentication',
34+
'preferredRequestBodyType'
3435
],
3536
expectedOptions = {
3637
collapseFolders: {
3738
name: 'Collapse redundant folders',
3839
type: 'boolean',
3940
default: true,
4041
description: 'Importing will collapse all folders that have only one child element and lack ' +
41-
'persistent folder-level data.'
42+
'persistent folder-level data.'
4243
},
4344
requestParametersResolution: {
4445
name: 'Request parameter generation',
4546
type: 'enum',
4647
default: 'Schema',
4748
availableOptions: ['Example', 'Schema'],
4849
description: 'Select whether to generate the request parameters based on the' +
49-
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
50-
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
51-
' in the schema.'
50+
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
51+
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
52+
' in the schema.'
5253
},
5354
exampleParametersResolution: {
5455
name: 'Response parameter generation',
5556
type: 'enum',
5657
default: 'Example',
5758
availableOptions: ['Example', 'Schema'],
5859
description: 'Select whether to generate the response parameters based on the' +
59-
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
60-
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
61-
' in the schema.'
60+
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
61+
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
62+
' in the schema.'
6263
},
6364
folderStrategy: {
6465
name: 'Folder organization',
@@ -88,8 +89,8 @@ const optionIds = [
8889
default: 'Fallback',
8990
availableOptions: ['Url', 'Fallback'],
9091
description: 'Determines how the requests inside the generated collection will be named.' +
91-
' If “Fallback” is selected, the request will be named after one of the following schema' +
92-
' values: `summary`, `operationId`, `description`, `url`.'
92+
' If “Fallback” is selected, the request will be named after one of the following schema' +
93+
' values: `summary`, `operationId`, `description`, `url`.'
9394
},
9495
schemaFaker: {
9596
name: 'Enable Schema Faking',
@@ -210,9 +211,9 @@ const optionIds = [
210211
default: 'Schema',
211212
availableOptions: ['Example', 'Schema'],
212213
description: 'Select whether to generate the request and response parameters based on the' +
213-
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
214-
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
215-
' in the schema.',
214+
' [schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject) or the' +
215+
' [example](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject)' +
216+
' in the schema.',
216217
external: true,
217218
usage: ['CONVERSION']
218219
},
@@ -232,6 +233,16 @@ const optionIds = [
232233
'the collection.',
233234
external: true,
234235
usage: ['CONVERSION']
236+
}, preferredRequestBodyType: {
237+
name: 'Select request body type',
238+
type: 'enum',
239+
default: 'first-listed',
240+
availableOptions: ['x-www-form-urlencoded', 'form-data', 'raw', 'first-listed'],
241+
description: 'When there are multiple content-types defined in the request body of OpenAPI, the conversion ' +
242+
'selects the preferred option content-type as request body.If "first-listed" is set, the first ' +
243+
'content-type defined in the OpenAPI spec will be selected.',
244+
external: false,
245+
usage: ['CONVERSION']
235246
}
236247
};
237248

@@ -312,8 +323,8 @@ describe('getOptions', function() {
312323
describe('OPTIONS.md', function() {
313324
it('must contain all details of options', function () {
314325
const optionsDoc = fs.readFileSync('OPTIONS.md', 'utf-8'),
315-
v1Options = getOptions(undefined, { external: true, moduleVersion: 'v1' }),
316-
v2Options = getOptions(undefined, { external: true, moduleVersion: 'v2' }),
326+
v1Options = getOptions(undefined, { moduleVersion: 'v1' }),
327+
v2Options = getOptions(undefined, { moduleVersion: 'v2' }),
317328
allOptions = _.uniqBy(_.concat(v1Options, v2Options), 'id');
318329

319330
expect(optionsDoc).to.eql(generateOptionsDoc(allOptions));

test/unit/schemaUtilsV2.test.js

+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
const {
2+
resolveRequestBodyForPostmanRequest
3+
} = require('../../libV2/schemaUtils.js'),
4+
concreteUtils = require('../../lib/30XUtils/schemaUtils30X'),
5+
expect = require('chai').expect,
6+
7+
// Example operationItem
8+
operationItem = {
9+
put: {
10+
'tags': [
11+
'Administration: Users'
12+
],
13+
'summary': 'Create or Update User',
14+
'operationId': 'User',
15+
'requestBody': {
16+
'content': {
17+
'application/json': {
18+
'schema': {
19+
'type': 'object',
20+
'properties': {
21+
'foo': {
22+
'type': 'string'
23+
}
24+
}
25+
}
26+
},
27+
'text/json': {
28+
'schema': {
29+
'type': 'object',
30+
'properties': {
31+
'foo': {
32+
'type': 'string'
33+
}
34+
}
35+
}
36+
},
37+
'application/xml': {
38+
'schema': {
39+
'type': 'object',
40+
'properties': {
41+
'foo': {
42+
'type': 'string'
43+
}
44+
}
45+
}
46+
},
47+
'multipart/form-data': {
48+
'schema': {
49+
'type': 'object',
50+
'properties': {
51+
'foo': {
52+
'type': 'string'
53+
}
54+
}
55+
}
56+
},
57+
'application/x-www-form-urlencoded': {
58+
'schema': {
59+
'type': 'object',
60+
'properties': {
61+
'foo': {
62+
'type': 'string'
63+
}
64+
}
65+
}
66+
}
67+
},
68+
'description': 'The User request.',
69+
'required': true
70+
},
71+
'responses': {
72+
'200': {
73+
'description': 'OK',
74+
'content': {
75+
'application/json': {
76+
'schema': {
77+
'type': 'object',
78+
'properties': {}
79+
}
80+
}
81+
}
82+
}
83+
}
84+
}
85+
};
86+
87+
describe('resolveRequestBodyForPostmanRequest function', function () {
88+
89+
it('should return first-listed request body when preferredRequestBodyType is not set', function () {
90+
const contextTest = {
91+
concreteUtils,
92+
schemaCache: {},
93+
schemaFakerCache: {},
94+
computedOptions: {
95+
parametersResolution: 'schema'
96+
}
97+
},
98+
operationItemTest = operationItem.put,
99+
result = resolveRequestBodyForPostmanRequest(contextTest, operationItemTest);
100+
101+
expect(result.body.mode).to.equal('raw');
102+
});
103+
104+
it('should return first-listed request body when preferredRequestBodyType is not a valid option', function () {
105+
const contextTest = {
106+
concreteUtils,
107+
schemaCache: {},
108+
schemaFakerCache: {},
109+
computedOptions: {
110+
parametersResolution: 'schema',
111+
preferredRequestBodyType: 'foo-bar'
112+
}
113+
},
114+
operationItemTest = operationItem.put,
115+
result = resolveRequestBodyForPostmanRequest(contextTest, operationItemTest);
116+
117+
expect(result.body.mode).to.equal('raw');
118+
});
119+
120+
it('should return encoded request body when preferredRequestBodyType is x-www-form-urlencoded', function () {
121+
const contextTest = {
122+
concreteUtils,
123+
schemaCache: {},
124+
schemaFakerCache: {},
125+
computedOptions: {
126+
parametersResolution: 'schema',
127+
preferredRequestBodyType: 'x-www-form-urlencoded'
128+
}
129+
},
130+
operationItemTest = operationItem.put,
131+
result = resolveRequestBodyForPostmanRequest(contextTest, operationItemTest);
132+
133+
expect(result.body.mode).to.equal('urlencoded');
134+
});
135+
136+
it('should return form data request body when preferredRequestBodyType is form-data', function () {
137+
const contextTest = {
138+
concreteUtils,
139+
schemaCache: {},
140+
schemaFakerCache: {},
141+
computedOptions: {
142+
parametersResolution: 'schema',
143+
preferredRequestBodyType: 'form-data'
144+
}
145+
},
146+
operationItemTest = operationItem.put,
147+
result = resolveRequestBodyForPostmanRequest(contextTest, operationItemTest);
148+
149+
expect(result.body.mode).to.equal('formdata');
150+
});
151+
152+
it('should return raw request body when preferredRequestBodyType is raw', function () {
153+
const contextTest = {
154+
concreteUtils,
155+
schemaCache: {},
156+
schemaFakerCache: {},
157+
computedOptions: {
158+
parametersResolution: 'schema',
159+
preferredRequestBodyType: 'raw'
160+
}
161+
},
162+
operationItemTest = operationItem.put,
163+
result = resolveRequestBodyForPostmanRequest(contextTest, operationItemTest);
164+
165+
expect(result.body.mode).to.equal('raw');
166+
});
167+
168+
it('should return raw request body when preferredRequestBodyType is first-listed', function () {
169+
const contextTest = {
170+
concreteUtils,
171+
schemaCache: {},
172+
schemaFakerCache: {},
173+
computedOptions: {
174+
parametersResolution: 'schema',
175+
preferredRequestBodyType: 'first-listed'
176+
}
177+
},
178+
operationItemTest = operationItem.put,
179+
result = resolveRequestBodyForPostmanRequest(contextTest, operationItemTest);
180+
181+
expect(result.body.mode).to.equal('raw');
182+
});
183+
184+
});

0 commit comments

Comments
 (0)