openapi-to-postmanv2
Version:
Convert a given OpenAPI specification to Postman Collection v2.0
495 lines (419 loc) • 14.4 kB
JavaScript
let _ = require('lodash'),
Graph = require('graphlib').Graph,
PATH_WEBHOOK = 'path~webhook',
ALLOWED_HTTP_METHODS = {
get: true,
head: true,
post: true,
put: true,
patch: true,
delete: true,
connect: true,
options: true,
trace: true
},
_generateTreeFromPathsV2 = function (openapi, { includeDeprecated }) {
/**
* We will create a unidirectional graph
*/
let tree = new Graph();
tree.setNode('root:collection', {
type: 'collection',
data: {},
meta: {}
});
/**
* Get all the paths sorted in desc order.
*/
const paths = Object.keys(openapi.paths);
if (_.isEmpty(paths)) {
return tree;
}
_.forEach(paths, function (completePath) {
let pathSplit = completePath === '/' ? [completePath] : _.compact(completePath.split('/'));
/**
* /user
* /team
* /hi
* /bye
*
* In this scenario, always create a base folder for the path
* and then add and link the request inside the created folder.
*/
if (pathSplit.length === 1) {
let methods = openapi.paths[completePath];
_.forEach(methods, function (data, method) {
if (!ALLOWED_HTTP_METHODS[method]) {
return;
}
/**
* include deprecated handling.
* If true, add in the postman collection. If false ignore the request.
*/
if (!includeDeprecated && data.deprecated) {
return;
}
if (!tree.hasNode(`path:folder:${pathSplit[0]}`)) {
tree.setNode(`path:folder:${pathSplit[0]}`, {
type: 'folder',
meta: {
name: pathSplit[0],
path: pathSplit[0],
pathIdentifier: pathSplit[0]
},
data: {}
});
tree.setEdge('root:collection', `path:folder:${pathSplit[0]}`);
}
tree.setNode(`path:request:${pathSplit[0]}:${method}`, {
type: 'request',
data: {},
meta: {
path: completePath,
method: method,
pathIdentifier: pathSplit[0]
}
});
tree.setEdge(`path:folder:${pathSplit[0]}`, `path:request:${pathSplit[0]}:${method}`);
});
}
else {
_.forEach(pathSplit, function (path, index) {
let previousPathIdentified = pathSplit.slice(0, index).join('/'),
pathIdentifier = pathSplit.slice(0, index + 1).join('/');
if ((index + 1) === pathSplit.length) {
let methods = openapi.paths[completePath];
_.forEach(methods, function (data, method) {
if (!ALLOWED_HTTP_METHODS[method]) {
return;
}
/**
* include deprecated handling.
* If true, add in the postman collection. If false ignore the request.
*/
if (!includeDeprecated && data.deprecated) {
return;
}
/**
* If it is the last node,
* it might happen that this exists as a folder.
*
* If yes add a request inside that folder else
* add as a request on the previous path idendified which will be a folder.
*/
if (!tree.hasNode(`path:folder:${pathIdentifier}`)) {
tree.setNode(`path:folder:${pathIdentifier}`, {
type: 'folder',
meta: {
name: path,
path: path,
pathIdentifier: pathIdentifier
},
data: {}
});
tree.setEdge(index === 0 ? 'root:collection' : `path:folder:${previousPathIdentified}`,
`path:folder:${pathIdentifier}`);
}
tree.setNode(`path:request:${pathIdentifier}:${method}`, {
type: 'request',
data: {},
meta: {
path: completePath,
method: method,
pathIdentifier: pathIdentifier
}
});
tree.setEdge(`path:folder:${pathIdentifier}`, `path:request:${pathIdentifier}:${method}`);
});
}
else {
let fromNode = index === 0 ? 'root:collection' : `path:folder:${previousPathIdentified}`,
toNode = `path:folder:${pathIdentifier}`;
if (!tree.hasNode(toNode)) {
tree.setNode(toNode, {
type: 'folder',
meta: {
name: path,
path: path,
pathIdentifier: pathIdentifier
},
data: {}
});
}
if (!tree.hasEdge(fromNode, toNode)) {
tree.setEdge(fromNode, toNode);
}
}
});
}
});
return tree;
},
// _generateTreeFromPaths = function (openapi, { includeDeprecated }) {
// /**
// * We will create a unidirectional graph
// */
// let tree = new Graph();
// tree.setNode('root:collection', {
// type: 'collection',
// data: {},
// meta: {}
// });
// _.forEach(openapi.paths, function (methods, path) {
// let pathSplit = path === '/' ? [path] : _.compact(path.split('/'));
// // if after path split we just have one entry
// // that means no folders need to be generated.
// // check for all the methods inside it and expand.
// if (pathSplit.length === 1) {
// /**
// * Always first try to find the node if it already exists.
// * if yes, bail out nothing is needed to be done.
// *
// * if the path length is 1, then also generate
// * the folder otherwise /pet and /pet/:id will never be in same folder.
// */
// // if (!tree.hasNode(`path:${pathSplit[0]}`)) {
// // tree.setNode(`path:${pathSplit[0]}`, {
// // type: 'folder',
// // meta: {
// // name: pathSplit[0],
// // path: pathSplit[0],
// // pathIdentifier: pathIdentifier
// // },
// // data: {}
// // });
// // tree.setEdge('root:collection', `path:${pathSplit[0]}`);
// // }
// _.forEach(methods, function (data, method) {
// if (!ALLOWED_HTTP_METHODS[method]) {
// return;
// }
// /**
// * include deprecated handling.
// * If true, add in the postman collection. If false ignore the request.
// */
// if (!includeDeprecated && data.deprecated) {
// return;
// }
// tree.setNode(`path:${pathSplit[0]}:${method}`, {
// type: 'request',
// meta: {
// path: path,
// method: method,
// pathIdentifier: pathSplit[0]
// },
// data: {}
// });
// tree.setEdge(`path:${pathSplit[0]}`, `path:${pathSplit[0]}:${method}`);
// });
// }
// else {
// _.forEach(pathSplit, function (p, index) {
// let previousPathIdentified = pathSplit.slice(0, index).join('/'),
// pathIdentifier = pathSplit.slice(0, index + 1).join('/');
// /**
// * Always first try to find the node if it already exists.
// * if yes, bail out nothing is needed to be done.
// */
// if (tree.hasNode(`path:${pathIdentifier}`)) {
// return;
// }
// else {
// tree.setNode(`path:${pathIdentifier}`, {
// type: 'folder',
// meta: {
// name: p,
// path: p,
// pathIdentifier: pathIdentifier
// },
// data: {}
// });
// /**
// * If index is 0, this means that we are on the first level.
// * Hence it is folder/request to be added on the first level
// *
// * If after the split we have more than one paths, then we need
// * to add to the previous node.
// */
// tree.setEdge(index === 0 ? 'root:collection' : `path:${previousPathIdentified}`, `path:${pathIdentifier}`);
// }
// });
// /**
// * Now for all the methods present in the path, add the request nodes.
// */
// _.forEach(methods, function (data, method) {
// if (!ALLOWED_HTTP_METHODS[method]) {
// return;
// }
// /**
// * include deprecated handling.
// * If true, add in the postman collection. If false ignore the request.
// */
// if (!includeDeprecated && data.deprecated) {
// return;
// }
// // join till the last path i.e. the folder.
// let previousPathIdentified = pathSplit.slice(0, (pathSplit.length)).join('/'),
// pathIdentifier = `${pathSplit.join('/')}:${method}`;
// tree.setNode(`path:${pathIdentifier}`, {
// type: 'request',
// data: {},
// meta: {
// path: path,
// method: method,
// pathIdentifier: pathIdentifier
// }
// });
// tree.setEdge(`path:${previousPathIdentified}`, `path:${pathIdentifier}`);
// });
// }
// });
// return tree;
// },
_generateTreeFromTags = function (openapi, { includeDeprecated }) {
let tree = new Graph(),
tagDescMap = _.reduce(openapi.tags, function (acc, data) {
acc[data.name] = data.description;
return acc;
}, {});
tree.setNode('root:collection', {
type: 'collection',
data: {},
meta: {}
});
/**
* Create folders for all the tags present.
*/
_.forEach(tagDescMap, function (desc, tag) {
if (tree.hasNode(`path:${tag}`)) {
return;
}
/**
* Generate a folder node and attach to root of collection.
*/
tree.setNode(`path:${tag}`, {
type: 'folder',
meta: {
path: '',
name: tag,
description: tagDescMap[tag]
},
data: {}
});
tree.setEdge('root:collection', `path:${tag}`);
});
_.forEach(openapi.paths, function (methods, path) {
_.forEach(methods, function (data, method) {
if (!ALLOWED_HTTP_METHODS[method]) {
return;
}
/**
* include deprecated handling.
* If true, add in the postman collection. If false ignore the request.
*/
if (!includeDeprecated && data.deprecated) {
return;
}
/**
* For all the tags present. Make that request to be
* referenced in all the folder which are applicable.
*/
if (data.tags && data.tags.length > 0) {
_.forEach(data.tags, function (tag) {
tree.setNode(`path:${tag}:${path}:${method}`, {
type: 'request',
data: {},
meta: {
tag: tag,
path: path,
method: method
}
});
// safeguard just in case there is no folder created for this tag.
if (!tree.hasNode(`path:${tag}`)) {
tree.setNode(`path:${tag}`, {
type: 'folder',
meta: {
path: path,
name: tag,
description: tagDescMap[tag]
},
data: {}
});
tree.setEdge('root:collection', `path:${tag}`);
}
tree.setEdge(`path:${tag}`, `path:${tag}:${path}:${method}`);
});
}
else {
tree.setNode(`path:${path}:${method}`, {
type: 'request',
data: {},
meta: {
path: path,
method: method
}
});
tree.setEdge('root:collection', `path:${path}:${method}`);
}
});
});
return tree;
},
_generateWebhookEndpoints = function (openapi, tree, { includeDeprecated }) {
if (!_.isEmpty(openapi.webhooks)) {
tree.setNode(`${PATH_WEBHOOK}:folder`, {
type: 'webhook~folder',
meta: {
path: 'webhook~folder',
name: 'webhook~folder',
description: ''
},
data: {}
});
tree.setEdge('root:collection', `${PATH_WEBHOOK}:folder`);
}
_.forEach(openapi.webhooks, function (methodData, path) {
_.forEach(methodData, function (data, method) {
/**
* include deprecated handling.
* If true, add in the postman collection. If false ignore the request.
*/
if (!includeDeprecated && data.deprecated) {
return;
}
tree.setNode(`${PATH_WEBHOOK}:${path}:${method}`, {
type: 'webhook~request',
meta: { path: path, method: method },
data: {}
});
tree.setEdge(`${PATH_WEBHOOK}:folder`, `${PATH_WEBHOOK}:${path}:${method}`);
});
});
return tree;
};
/**
* Used to generate a tree skeleton for the openapi which will be a collection
*
* @param {Object} openapi - openapi schema paths in question
* @param {String} stratergy='PATHS'
*
* @returns {Object} - tree format
*/
module.exports = function (openapi, { folderStrategy, includeWebhooks, includeDeprecated }) {
let skeletonTree;
switch (folderStrategy) {
case 'tags':
skeletonTree = _generateTreeFromTags(openapi, { includeDeprecated });
break;
case 'paths':
skeletonTree = _generateTreeFromPathsV2(openapi, { includeDeprecated });
break;
default:
throw new Error('generateSkeletonTreeFromOpenAPI~folderStrategy not valid');
}
if (includeWebhooks) {
skeletonTree = _generateWebhookEndpoints(openapi, skeletonTree, { includeDeprecated });
}
return skeletonTree;
};