Skip to content

Commit

Permalink
Merge pull request #731 from postmanlabs/feature/xml-schema-body-data…
Browse files Browse the repository at this point in the history
…-support

Added proper support for usage of examples in cases of XML type of body.
  • Loading branch information
VShingala committed Jun 7, 2023
2 parents 46ed506 + d5821ab commit 9a5dd63
Show file tree
Hide file tree
Showing 9 changed files with 360 additions and 224 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Added

- Added support for consumption of schema level examples while generating data from XML schemas.

### Fixed

- Fixed the default value of auth in the generated request when it is not resolved.
Expand Down
32 changes: 17 additions & 15 deletions lib/schemaUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const { formatDataPath, checkIsCorrectType, isKnownType } = require('./common/sc
deref = require('./deref.js'),
_ = require('lodash'),
xmlFaker = require('./xmlSchemaFaker.js'),
js2xml = require('./common/js2xml.js'),
openApiErr = require('./error.js'),
ajvValidationError = require('./ajValidation/ajvValidationError'),
utils = require('./utils.js'),
Expand Down Expand Up @@ -242,7 +241,7 @@ function safeSchemaFaker (oldSchema, resolveTo, resolveFor, parameterSourceOptio

try {
if (schemaFormat === SCHEMA_FORMATS.XML) {
fakedSchema = xmlFaker(null, resolvedSchema, indentCharacter);
fakedSchema = xmlFaker(null, resolvedSchema, indentCharacter, resolveTo);
schemaFakerCache[key] = fakedSchema;
return fakedSchema;
}
Expand Down Expand Up @@ -1607,15 +1606,27 @@ module.exports = {

// Convert example into XML if present as JSON data
if (contentType === TEXT_XML || contentType === APP_XML || headerFamily === HEADER_TYPE.XML) {
bodyData = js2xml(bodyData, indentCharacter);
let bodySchemaWithExample = bodyObj.schema;

// Assign example at schema level to be faked by xmlSchemaFaker
if (typeof bodyObj.schema === 'object') {
bodySchemaWithExample = Object.assign({}, bodyObj.schema, { example: bodyData });
}
bodyData = xmlFaker(null, bodySchemaWithExample, indentCharacter, resolveTo);
}
}
else if (!_.isEmpty(bodyObj.examples) && (resolveTo === 'example' || !bodyObj.schema)) {
// take one of the examples as the body and not all
bodyData = this.getExampleData(bodyObj.examples, components, options);

if (contentType === TEXT_XML || contentType === APP_XML || headerFamily === HEADER_TYPE.XML) {
bodyData = js2xml(bodyData, indentCharacter);
let bodySchemaWithExample = bodyObj.schema;

// Assign example at schema level to be faked by xmlSchemaFaker
if (typeof bodyObj.schema === 'object') {
bodySchemaWithExample = Object.assign({}, bodyObj.schema, { example: bodyData });
}
bodyData = xmlFaker(null, bodySchemaWithExample, indentCharacter, resolveTo);
}
}
else if (bodyObj.schema) {
Expand Down Expand Up @@ -1652,17 +1663,8 @@ module.exports = {
return '<Error: Spec size too large, skipping faking of schemas>';
}

if (
resolveTo === 'example' &&
_.get(bodyObj.schema, 'example') !== undefined &&
(contentType === TEXT_XML || contentType === APP_XML || headerFamily === HEADER_TYPE.XML)
) {
bodyData = js2xml(bodyObj.schema.example, indentCharacter);
}
else {
bodyData = safeSchemaFaker(bodyObj.schema || {}, resolveTo, PROCESSING_TYPE.CONVERSION, parameterSourceOption,
components, schemaFormat, schemaCache, options);
}
bodyData = safeSchemaFaker(bodyObj.schema || {}, resolveTo, PROCESSING_TYPE.CONVERSION, parameterSourceOption,
components, schemaFormat, schemaCache, options);
}
else {
// do not fake if the option is false
Expand Down
96 changes: 68 additions & 28 deletions lib/xmlSchemaFaker.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
/* eslint-disable */
const _ = require('lodash');
const _ = require('lodash'),
js2xml = require('../lib/common/js2xml');

function convertSchemaToXML(name, schema, attribute, indentChar, indent) {
function indentContent (content, initialIndent) {
let contentArr = _.split(content, '\n'),
indentedContent = _.join(_.map(contentArr, (contentElement) => { return initialIndent + contentElement; }), '\n');

return indentedContent;
}

function convertSchemaToXML(name, schema, attribute, indentChar, indent, resolveTo) {
var tagPrefix = '',
cIndent = _.times(indent, _.constant(indentChar)).join('');
cIndent = _.times(indent, _.constant(indentChar)).join(''),
retVal = '';

const schemaExample = typeof schema === 'object' && (schema.example);

name = _.get(schema, 'xml.name', name || 'element');
if (_.get(schema, 'xml.prefix')) {
tagPrefix = schema.xml.prefix ? `${schema.xml.prefix}:` : '';
Expand All @@ -21,53 +33,81 @@ function convertSchemaToXML(name, schema, attribute, indentChar, indent) {
else if (schema.type === 'number') {
actualValue = '(number)';
}

if (resolveTo === 'example' && typeof schemaExample !== 'undefined') {
actualValue = schemaExample;
}

if (attribute) {
return actualValue;
}
else {
var retVal = `\n${cIndent}<${tagPrefix+name}`;
retVal = `\n${cIndent}<${tagPrefix+name}`;
if (_.get(schema, 'xml.namespace')) {
retVal += ` xmlns:${tagPrefix.slice(0,-1)}="${schema.xml.namespace}"`
}
retVal += `>${actualValue}</${tagPrefix}${name}>`;
}
}
else if (schema.type === 'object') {
// go through all properties
var retVal = '\n' + cIndent + `<${tagPrefix}${name}`, propVal, attributes = [], childNodes = '';
if (_.get(schema, 'xml.namespace')) {
let formattedTagPrefix = tagPrefix ?
`:${tagPrefix.slice(0,-1)}` :
'';
retVal += ` xmlns${formattedTagPrefix}="${schema.xml.namespace}"`
if (resolveTo === 'example' && typeof schemaExample !== 'undefined') {
const elementName = _.get(schema, 'items.xml.name', name || 'element'),
fakedContent = js2xml({ [elementName]: schemaExample }, indentChar);

retVal = '\n' + indentContent(fakedContent, cIndent);
}
_.forOwn(schema.properties, (value, key) => {
propVal = convertSchemaToXML(key, value, _.get(value, 'xml.attribute'), indentChar, indent + 1);
if (_.get(value, 'xml.attribute')) {
attributes.push(`${key}="${propVal}"`);
else {
// go through all properties
var propVal, attributes = [], childNodes = '';

retVal = '\n' + cIndent + `<${tagPrefix}${name}`;

if (_.get(schema, 'xml.namespace')) {
let formattedTagPrefix = tagPrefix ?
`:${tagPrefix.slice(0,-1)}` :
'';
retVal += ` xmlns${formattedTagPrefix}="${schema.xml.namespace}"`
}
else {
childNodes += _.isString(propVal) ? propVal : '';
_.forOwn(schema.properties, (value, key) => {
propVal = convertSchemaToXML(key, value, _.get(value, 'xml.attribute'), indentChar, indent + 1, resolveTo);
if (_.get(value, 'xml.attribute')) {
attributes.push(`${key}="${propVal}"`);
}
else {
childNodes += _.isString(propVal) ? propVal : '';
}
});
if (attributes.length > 0) {
retVal += ' ' + attributes.join(' ');
}
});
if (attributes.length > 0) {
retVal += ' ' + attributes.join(' ');
retVal += '>';
retVal += childNodes;
retVal += `\n${cIndent}</${tagPrefix}${name}>`;
}
retVal += '>';
retVal += childNodes;
retVal += `\n${cIndent}</${tagPrefix}${name}>`;
}
else if (schema.type === 'array') {
// schema.items must be an object
var isWrapped = _.get(schema, 'xml.wrapped'),
extraIndent = isWrapped ? 1 : 0,
arrayElemName = _.get(schema, 'items.xml.name', name, 'arrayItem'),
arrayElemName = _.get(schema, 'items.xml.name', name || 'element'),
schemaItemsWithXmlProps = _.cloneDeep(schema.items),
contents;

schemaItemsWithXmlProps.xml = schema.xml;
contents = convertSchemaToXML(arrayElemName, schemaItemsWithXmlProps, false, indentChar, indent + extraIndent) +
convertSchemaToXML(arrayElemName, schemaItemsWithXmlProps, false, indentChar, indent + extraIndent);

if (resolveTo === 'example' && typeof schemaExample !== 'undefined') {
const fakedContent = js2xml({ [arrayElemName]: schemaExample }, indentChar);

contents = '\n' + indentContent(fakedContent, cIndent);
}
else {
let singleElementContent = convertSchemaToXML(arrayElemName, schemaItemsWithXmlProps, false, indentChar,
indent + extraIndent, resolveTo);

// Atleast 2 items per array will be added asame as JSON schema faker
contents = singleElementContent + singleElementContent;
}

if (isWrapped) {
return `\n${cIndent}<${tagPrefix}${name}>${contents}\n${cIndent}</${tagPrefix}${name}>`;
}
Expand All @@ -78,9 +118,9 @@ function convertSchemaToXML(name, schema, attribute, indentChar, indent) {
return retVal;
}

module.exports = function(name, schema, indentCharacter) {
module.exports = function(name, schema, indentCharacter, resolveTo) {
// substring(1) to trim the leading newline
return convertSchemaToXML(name, schema, false, indentCharacter, 0).substring(1);
return convertSchemaToXML(name, schema, false, indentCharacter, 0, resolveTo).substring(1);
};
/*
a = convertSchemaToXML('Person',{
Expand Down
14 changes: 10 additions & 4 deletions libV2/schemaUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const schemaFaker = require('../assets/json-schema-faker'),
_ = require('lodash'),
mergeAllOf = require('json-schema-merge-allof'),
xmlFaker = require('./xmlSchemaFaker.js'),
js2xml = require('../lib/common/js2xml'),
URLENCODED = 'application/x-www-form-urlencoded',
APP_JSON = 'application/json',
APP_JS = 'application/javascript',
Expand Down Expand Up @@ -862,7 +861,7 @@ let QUERYPARAM = 'query',

try {
if (schemaFormat === SCHEMA_FORMATS.XML) {
return xmlFaker(null, resolvedSchema, indentCharacter);
return xmlFaker(null, resolvedSchema, indentCharacter, parametersResolution);
}

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

if (bodyType === APP_XML || bodyType === TEXT_XML || headerFamily === HEADER_TYPE.XML) {
bodyData = js2xml(exampleData, indentCharacter);
let reqBodySchemaWithExample = requestBodySchema;

// Assign example at schema level to be faked by xmlSchemaFaker
if (typeof requestBodySchema === 'object') {
reqBodySchemaWithExample = Object.assign({}, requestBodySchema, { example: exampleData });
}

return xmlFaker(null, reqBodySchemaWithExample, indentCharacter, parametersResolution);
}
else {
bodyData = exampleData;
Expand All @@ -1157,7 +1163,7 @@ let QUERYPARAM = 'query',
}

if (bodyType === APP_XML || bodyType === TEXT_XML || headerFamily === HEADER_TYPE.XML) {
return xmlFaker(null, requestBodySchema, indentCharacter);
return xmlFaker(null, requestBodySchema, indentCharacter, parametersResolution);
}


Expand Down
Loading

0 comments on commit 9a5dd63

Please sign in to comment.