Skip to content

Commit 9a5dd63

Browse files
authored
Merge pull request #731 from postmanlabs/feature/xml-schema-body-data-support
Added proper support for usage of examples in cases of XML type of body.
2 parents 46ed506 + d5821ab commit 9a5dd63

File tree

9 files changed

+360
-224
lines changed

9 files changed

+360
-224
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- Added support for consumption of schema level examples while generating data from XML schemas.
8+
59
### Fixed
610

711
- Fixed the default value of auth in the generated request when it is not resolved.

lib/schemaUtils.js

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ const { formatDataPath, checkIsCorrectType, isKnownType } = require('./common/sc
1313
deref = require('./deref.js'),
1414
_ = require('lodash'),
1515
xmlFaker = require('./xmlSchemaFaker.js'),
16-
js2xml = require('./common/js2xml.js'),
1716
openApiErr = require('./error.js'),
1817
ajvValidationError = require('./ajValidation/ajvValidationError'),
1918
utils = require('./utils.js'),
@@ -242,7 +241,7 @@ function safeSchemaFaker (oldSchema, resolveTo, resolveFor, parameterSourceOptio
242241

243242
try {
244243
if (schemaFormat === SCHEMA_FORMATS.XML) {
245-
fakedSchema = xmlFaker(null, resolvedSchema, indentCharacter);
244+
fakedSchema = xmlFaker(null, resolvedSchema, indentCharacter, resolveTo);
246245
schemaFakerCache[key] = fakedSchema;
247246
return fakedSchema;
248247
}
@@ -1607,15 +1606,27 @@ module.exports = {
16071606

16081607
// Convert example into XML if present as JSON data
16091608
if (contentType === TEXT_XML || contentType === APP_XML || headerFamily === HEADER_TYPE.XML) {
1610-
bodyData = js2xml(bodyData, indentCharacter);
1609+
let bodySchemaWithExample = bodyObj.schema;
1610+
1611+
// Assign example at schema level to be faked by xmlSchemaFaker
1612+
if (typeof bodyObj.schema === 'object') {
1613+
bodySchemaWithExample = Object.assign({}, bodyObj.schema, { example: bodyData });
1614+
}
1615+
bodyData = xmlFaker(null, bodySchemaWithExample, indentCharacter, resolveTo);
16111616
}
16121617
}
16131618
else if (!_.isEmpty(bodyObj.examples) && (resolveTo === 'example' || !bodyObj.schema)) {
16141619
// take one of the examples as the body and not all
16151620
bodyData = this.getExampleData(bodyObj.examples, components, options);
16161621

16171622
if (contentType === TEXT_XML || contentType === APP_XML || headerFamily === HEADER_TYPE.XML) {
1618-
bodyData = js2xml(bodyData, indentCharacter);
1623+
let bodySchemaWithExample = bodyObj.schema;
1624+
1625+
// Assign example at schema level to be faked by xmlSchemaFaker
1626+
if (typeof bodyObj.schema === 'object') {
1627+
bodySchemaWithExample = Object.assign({}, bodyObj.schema, { example: bodyData });
1628+
}
1629+
bodyData = xmlFaker(null, bodySchemaWithExample, indentCharacter, resolveTo);
16191630
}
16201631
}
16211632
else if (bodyObj.schema) {
@@ -1652,17 +1663,8 @@ module.exports = {
16521663
return '<Error: Spec size too large, skipping faking of schemas>';
16531664
}
16541665

1655-
if (
1656-
resolveTo === 'example' &&
1657-
_.get(bodyObj.schema, 'example') !== undefined &&
1658-
(contentType === TEXT_XML || contentType === APP_XML || headerFamily === HEADER_TYPE.XML)
1659-
) {
1660-
bodyData = js2xml(bodyObj.schema.example, indentCharacter);
1661-
}
1662-
else {
1663-
bodyData = safeSchemaFaker(bodyObj.schema || {}, resolveTo, PROCESSING_TYPE.CONVERSION, parameterSourceOption,
1664-
components, schemaFormat, schemaCache, options);
1665-
}
1666+
bodyData = safeSchemaFaker(bodyObj.schema || {}, resolveTo, PROCESSING_TYPE.CONVERSION, parameterSourceOption,
1667+
components, schemaFormat, schemaCache, options);
16661668
}
16671669
else {
16681670
// do not fake if the option is false

lib/xmlSchemaFaker.js

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
/* eslint-disable */
2-
const _ = require('lodash');
2+
const _ = require('lodash'),
3+
js2xml = require('../lib/common/js2xml');
34

4-
function convertSchemaToXML(name, schema, attribute, indentChar, indent) {
5+
function indentContent (content, initialIndent) {
6+
let contentArr = _.split(content, '\n'),
7+
indentedContent = _.join(_.map(contentArr, (contentElement) => { return initialIndent + contentElement; }), '\n');
8+
9+
return indentedContent;
10+
}
11+
12+
function convertSchemaToXML(name, schema, attribute, indentChar, indent, resolveTo) {
513
var tagPrefix = '',
6-
cIndent = _.times(indent, _.constant(indentChar)).join('');
14+
cIndent = _.times(indent, _.constant(indentChar)).join(''),
15+
retVal = '';
16+
17+
const schemaExample = typeof schema === 'object' && (schema.example);
18+
719
name = _.get(schema, 'xml.name', name || 'element');
820
if (_.get(schema, 'xml.prefix')) {
921
tagPrefix = schema.xml.prefix ? `${schema.xml.prefix}:` : '';
@@ -21,53 +33,81 @@ function convertSchemaToXML(name, schema, attribute, indentChar, indent) {
2133
else if (schema.type === 'number') {
2234
actualValue = '(number)';
2335
}
36+
37+
if (resolveTo === 'example' && typeof schemaExample !== 'undefined') {
38+
actualValue = schemaExample;
39+
}
40+
2441
if (attribute) {
2542
return actualValue;
2643
}
2744
else {
28-
var retVal = `\n${cIndent}<${tagPrefix+name}`;
45+
retVal = `\n${cIndent}<${tagPrefix+name}`;
2946
if (_.get(schema, 'xml.namespace')) {
3047
retVal += ` xmlns:${tagPrefix.slice(0,-1)}="${schema.xml.namespace}"`
3148
}
3249
retVal += `>${actualValue}</${tagPrefix}${name}>`;
3350
}
3451
}
3552
else if (schema.type === 'object') {
36-
// go through all properties
37-
var retVal = '\n' + cIndent + `<${tagPrefix}${name}`, propVal, attributes = [], childNodes = '';
38-
if (_.get(schema, 'xml.namespace')) {
39-
let formattedTagPrefix = tagPrefix ?
40-
`:${tagPrefix.slice(0,-1)}` :
41-
'';
42-
retVal += ` xmlns${formattedTagPrefix}="${schema.xml.namespace}"`
53+
if (resolveTo === 'example' && typeof schemaExample !== 'undefined') {
54+
const elementName = _.get(schema, 'items.xml.name', name || 'element'),
55+
fakedContent = js2xml({ [elementName]: schemaExample }, indentChar);
56+
57+
retVal = '\n' + indentContent(fakedContent, cIndent);
4358
}
44-
_.forOwn(schema.properties, (value, key) => {
45-
propVal = convertSchemaToXML(key, value, _.get(value, 'xml.attribute'), indentChar, indent + 1);
46-
if (_.get(value, 'xml.attribute')) {
47-
attributes.push(`${key}="${propVal}"`);
59+
else {
60+
// go through all properties
61+
var propVal, attributes = [], childNodes = '';
62+
63+
retVal = '\n' + cIndent + `<${tagPrefix}${name}`;
64+
65+
if (_.get(schema, 'xml.namespace')) {
66+
let formattedTagPrefix = tagPrefix ?
67+
`:${tagPrefix.slice(0,-1)}` :
68+
'';
69+
retVal += ` xmlns${formattedTagPrefix}="${schema.xml.namespace}"`
4870
}
49-
else {
50-
childNodes += _.isString(propVal) ? propVal : '';
71+
_.forOwn(schema.properties, (value, key) => {
72+
propVal = convertSchemaToXML(key, value, _.get(value, 'xml.attribute'), indentChar, indent + 1, resolveTo);
73+
if (_.get(value, 'xml.attribute')) {
74+
attributes.push(`${key}="${propVal}"`);
75+
}
76+
else {
77+
childNodes += _.isString(propVal) ? propVal : '';
78+
}
79+
});
80+
if (attributes.length > 0) {
81+
retVal += ' ' + attributes.join(' ');
5182
}
52-
});
53-
if (attributes.length > 0) {
54-
retVal += ' ' + attributes.join(' ');
83+
retVal += '>';
84+
retVal += childNodes;
85+
retVal += `\n${cIndent}</${tagPrefix}${name}>`;
5586
}
56-
retVal += '>';
57-
retVal += childNodes;
58-
retVal += `\n${cIndent}</${tagPrefix}${name}>`;
5987
}
6088
else if (schema.type === 'array') {
6189
// schema.items must be an object
6290
var isWrapped = _.get(schema, 'xml.wrapped'),
6391
extraIndent = isWrapped ? 1 : 0,
64-
arrayElemName = _.get(schema, 'items.xml.name', name, 'arrayItem'),
92+
arrayElemName = _.get(schema, 'items.xml.name', name || 'element'),
6593
schemaItemsWithXmlProps = _.cloneDeep(schema.items),
6694
contents;
6795

6896
schemaItemsWithXmlProps.xml = schema.xml;
69-
contents = convertSchemaToXML(arrayElemName, schemaItemsWithXmlProps, false, indentChar, indent + extraIndent) +
70-
convertSchemaToXML(arrayElemName, schemaItemsWithXmlProps, false, indentChar, indent + extraIndent);
97+
98+
if (resolveTo === 'example' && typeof schemaExample !== 'undefined') {
99+
const fakedContent = js2xml({ [arrayElemName]: schemaExample }, indentChar);
100+
101+
contents = '\n' + indentContent(fakedContent, cIndent);
102+
}
103+
else {
104+
let singleElementContent = convertSchemaToXML(arrayElemName, schemaItemsWithXmlProps, false, indentChar,
105+
indent + extraIndent, resolveTo);
106+
107+
// Atleast 2 items per array will be added asame as JSON schema faker
108+
contents = singleElementContent + singleElementContent;
109+
}
110+
71111
if (isWrapped) {
72112
return `\n${cIndent}<${tagPrefix}${name}>${contents}\n${cIndent}</${tagPrefix}${name}>`;
73113
}
@@ -78,9 +118,9 @@ function convertSchemaToXML(name, schema, attribute, indentChar, indent) {
78118
return retVal;
79119
}
80120

81-
module.exports = function(name, schema, indentCharacter) {
121+
module.exports = function(name, schema, indentCharacter, resolveTo) {
82122
// substring(1) to trim the leading newline
83-
return convertSchemaToXML(name, schema, false, indentCharacter, 0).substring(1);
123+
return convertSchemaToXML(name, schema, false, indentCharacter, 0, resolveTo).substring(1);
84124
};
85125
/*
86126
a = convertSchemaToXML('Person',{

libV2/schemaUtils.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const schemaFaker = require('../assets/json-schema-faker'),
55
_ = require('lodash'),
66
mergeAllOf = require('json-schema-merge-allof'),
77
xmlFaker = require('./xmlSchemaFaker.js'),
8-
js2xml = require('../lib/common/js2xml'),
98
URLENCODED = 'application/x-www-form-urlencoded',
109
APP_JSON = 'application/json',
1110
APP_JS = 'application/javascript',
@@ -862,7 +861,7 @@ let QUERYPARAM = 'query',
862861

863862
try {
864863
if (schemaFormat === SCHEMA_FORMATS.XML) {
865-
return xmlFaker(null, resolvedSchema, indentCharacter);
864+
return xmlFaker(null, resolvedSchema, indentCharacter, parametersResolution);
866865
}
867866

868867
// for JSON, the indentCharacter will be applied in the JSON.stringify step later on
@@ -1143,7 +1142,14 @@ let QUERYPARAM = 'query',
11431142
const exampleData = example || getExampleData(context, examples);
11441143

11451144
if (bodyType === APP_XML || bodyType === TEXT_XML || headerFamily === HEADER_TYPE.XML) {
1146-
bodyData = js2xml(exampleData, indentCharacter);
1145+
let reqBodySchemaWithExample = requestBodySchema;
1146+
1147+
// Assign example at schema level to be faked by xmlSchemaFaker
1148+
if (typeof requestBodySchema === 'object') {
1149+
reqBodySchemaWithExample = Object.assign({}, requestBodySchema, { example: exampleData });
1150+
}
1151+
1152+
return xmlFaker(null, reqBodySchemaWithExample, indentCharacter, parametersResolution);
11471153
}
11481154
else {
11491155
bodyData = exampleData;
@@ -1157,7 +1163,7 @@ let QUERYPARAM = 'query',
11571163
}
11581164

11591165
if (bodyType === APP_XML || bodyType === TEXT_XML || headerFamily === HEADER_TYPE.XML) {
1160-
return xmlFaker(null, requestBodySchema, indentCharacter);
1166+
return xmlFaker(null, requestBodySchema, indentCharacter, parametersResolution);
11611167
}
11621168

11631169

0 commit comments

Comments
 (0)