Skip to content

Feature/48 - Support Resource (path) level parameters cascading into operations #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 95 additions & 37 deletions convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ var uuidv4 = require('uuid/v4'),
this.basePath = '';
this.collectionId = '';
this.folders = {};
// Base parameters are the reference-able collection parameters
this.baseParams = {};
// Resource parameters are shared to all operations under the resource
this.resourceParams = {};
this.logger = function () {
};

Expand Down Expand Up @@ -83,8 +86,10 @@ var uuidv4 = require('uuid/v4'),
var segments = pathUrl.split('/'),
numSegments = segments.length,
folderName = null;

this.logger('Getting folder name for path: ' + pathUrl);
this.logger('Segments: ' + JSON.stringify(segments));

if (numSegments > 1) {
folderName = segments[1];

Expand Down Expand Up @@ -120,55 +125,41 @@ var uuidv4 = require('uuid/v4'),
this.collectionJson.description = json.info.description;
},

getParamsForPathItem: function (oldParams, newParams) {
getParamsForPathItem: function (params) {
var retVal = {},
numOldParams,
numNewParams,
numParams,
i,
parts,
lastPart,
getBaseParam;
lastPart;

oldParams = oldParams || [];
newParams = newParams || [];
// Ensure params are arrays of objects.
// The param be single-level nested objects if they come from the retVal of this method!

numOldParams = oldParams.length;
numNewParams = newParams.length;

for (i = 0; i < numOldParams; i++) {
if (oldParams[i].$ref) {
// this is a ref
if (oldParams[i].$ref.indexOf('#/parameters') === 0) {
parts = oldParams[i].$ref.split('/');
lastPart = parts[parts.length - 1];
getBaseParam = this.baseParams[lastPart];
retVal[lastPart] = getBaseParam;
}
}
else {
retVal[oldParams[i].name] = oldParams[i];
}
if (this.isObject(params)) {
params = this.paramsObjectToArray(params);
}

for (i = 0; i < numNewParams; i++) {
if (newParams[i].$ref) {
params = params || [];
numParams = params.length;

for (i = 0; i < numParams; i++) {
if (params[i].$ref) {
// this is a ref
if (newParams[i].$ref.indexOf('#/parameters') === 0) {
parts = newParams[i].$ref.split('/');
if (params[i].$ref.indexOf('#/parameters') === 0) {
parts = params[i].$ref.split('/');
lastPart = parts[parts.length - 1];
getBaseParam = this.baseParams[lastPart];
retVal[lastPart] = getBaseParam;
retVal[lastPart] = this.baseParams[lastPart];
}
}
else {
retVal[newParams[i].name] = newParams[i];
retVal[params[i].name] = params[i];
}
}

return retVal;
},

addOperationToFolder: function (path, method, operation, folderName, params) {
addOperationToFolder: function (path, method, operation, folderName) {
var root = this,
request = {
'id': uuidv4(),
Expand All @@ -189,7 +180,8 @@ var uuidv4 = require('uuid/v4'),
'collectionId': root.collectionId,
'synced': false
},
thisParams = this.getParamsForPathItem(params, operation.parameters),
thisParams = this.getParamsForPathItem(
this.mergeObjectArrays(this.resourceParams, operation.parameters)),
hasQueryParams = false,
param,
requestAttr,
Expand Down Expand Up @@ -319,7 +311,8 @@ var uuidv4 = require('uuid/v4'),
return;
}

var paramsForPathItem = this.getParamsForPathItem(this.baseParams, pathItem.parameters),
var paramsForPathItem = this.getParamsForPathItem(
this.mergeObjectArrays(pathItem.parameters, this.resourceParams)),
acceptedPostmanVerbs = [
'get', 'put', 'post', 'patch', 'delete', 'copy', 'head', 'options',
'link', 'unlink', 'purge', 'lock', 'unlock', 'propfind', 'view'],
Expand All @@ -335,6 +328,8 @@ var uuidv4 = require('uuid/v4'),
for (i = 0; i < numVerbs; i++) {
verb = acceptedPostmanVerbs[i];
if (pathItem[verb]) {
this.logger('Adding Operation to Folder: ' + verb.toUpperCase() + ' ' + path);

this.addOperationToFolder(
path,
verb.toUpperCase(),
Expand All @@ -347,16 +342,28 @@ var uuidv4 = require('uuid/v4'),
},

handlePaths: function (json) {
var paths = json.paths,
var i,
paths = json.paths,
path,
folderName;

// Add a folder for each path
for (path in paths) {
if (paths.hasOwnProperty(path)) {
folderName = this.getFolderNameForPath(path);
this.logger('Adding path item. path = ' + path + ' folder = ' + folderName);
this.addPathItemToFolder(path, paths[path], folderName);
this.logger('Adding path item. path = ' + path + ' folder = ' + folderName);

// Update a specific Operations parameters with any parent Resource parameters.
this.resourceParams = [];

if (path.startsWith('/')) {
if (paths[path].parameters) {
for (i = 0; i < paths[path].parameters.length; i++) {
this.resourceParams.push(paths[path].parameters[i]);
}
}
this.addPathItemToFolder(path, paths[path], folderName);
}
}
}
},
Expand Down Expand Up @@ -398,6 +405,7 @@ var uuidv4 = require('uuid/v4'),

this.globalProduces = json.produces || [];

// Pull reference-able parameter definitions into memory
this.handleParams(json.parameters, 'collection');

this.handleInfo(json);
Expand All @@ -409,7 +417,7 @@ var uuidv4 = require('uuid/v4'),
this.addFoldersToCollection();

this.collectionJson.id = this.collectionId;
// this.logger(JSON.stringify(this.collectionJson));

this.logger('Swagger converted successfully');

validationResult.collection = this.collectionJson;
Expand All @@ -420,6 +428,56 @@ var uuidv4 = require('uuid/v4'),
// since travis doesnt support es6
endsWith: function (str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
},

/**
* Converts a params collection object into an arrow of param objects.
* @param {*} params
*/
paramsObjectToArray: function (params) {
var key,
result = [];
for (key in params) {
if (params.hasOwnProperty(key)) {
result.push(params[key]);
}
}
return result;
},

/**
* Merge the 2 objects; with the first object taking precedence on key-conflicts.
* @param {*} obj1 the assertive object.
* @param {*} obj2 the deferring object.
*/
mergeObjectArrays: function (obj1, obj2) {
var i,
result = [],
tracker = [];

obj1 = obj1 || [];
obj2 = obj2 || [];

for (i = 0; i < obj1.length; i++) {
result.push(obj1[i]);
tracker.push(obj1[i].name);
}

for (i = 0; i < obj2.length; i++) {
if (tracker.indexOf(obj2[i].name) === -1) {
result.push(obj2[i]);
}
}

return result;
},

/**
* Checks if the parameter is a JavaScript object
* @param {*} value
*/
isObject: function (value) {
return value && typeof value === 'object' && value.constructor === Object;
}
});

Expand Down
14 changes: 13 additions & 1 deletion test/converter-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('the converter', function () {
expect(convertWithoutOptionsResult.collection.requests[3].url.indexOf('{') > 0).to.be(true);
});

it('should convert path paramters to postman-compatible paramters', function () {
it('should convert path parameters to postman-compatible parameters', function () {
var samplePath = path.join(__dirname, 'data', 'swagger2-with-params.json'),
swagger = require(samplePath),
converter = new Swagger2Postman(),
Expand All @@ -66,4 +66,16 @@ describe('the converter', function () {
expect(convertResult.collection.requests[0].url.indexOf(':ownerId') > -1).to.be(true);
expect(convertResult.collection.requests[0].url.indexOf(':petId') > -1).to.be(true);
});

it('should convert path parameters to postman-compatible parameters', function () {
var samplePath = path.join(__dirname, 'data', 'swagger2-with-inherited-params.json'),
swagger = require(samplePath),
converter = new Swagger2Postman(),
convertResult = converter.convert(swagger);

expect(convertResult.collection.requests[0].pathVariables.operationParameter).to.be('{{operationParameter}}');
expect(convertResult.collection.requests[0].pathVariables.resourceParameter).to.be('{{resourceParameter}}');
expect(convertResult.collection.requests[0].pathVariables.unusedParameter).to.be(undefined);
expect(convertResult.collection.requests[0].pathVariables.referencedParameter).to.be('{{referencedParameter}}');
});
});
62 changes: 62 additions & 0 deletions test/data/swagger2-with-inherited-params.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"swagger": "2.0",
"info": {
"description": "My API",
"version": "1.0.0",
"title": "Awesome Test API",
"termsOfService": "http://www.domain.com",
"contact": {
"name": "[email protected]"
}
},
"basePath": "/",
"schemes": [
"http"
],
"paths": {
"/x/{resourceParameter}/y/{operationParameter}": {
"parameters": [{
"in": "path",
"name": "resourceParameter",
"description": "Parameter set at the Resource level",
"required": true,
"type": "integer"
}],
"post": {
"summary": "Test operation",
"description": "",
"operationId": "testOperation",
"parameters": [{
"in": "path",
"name": "operationParameter",
"description": "Parameter set at the Operation level",
"required": true,
"type": "integer"
}, {
"$ref": "#/parameters/referenced-parameter"
}],
"responses": {
"200": {
"description": "Test operation successful."
}
}
}
}
},
"parameters": {
"referenced-parameter": {
"name": "referencedParameter",
"description": "This is a referenced parameter",
"required": true,
"type": "string",
"in": "path"
},
"unused-parameter": {
"name": "unusedParameter",
"description": "This should never be included",
"required": true,
"type": "string",
"in": "path"
}
}
}