Skip to content
Merged
39 changes: 28 additions & 11 deletions lib/convert.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
const raml = require('raml-1-parser'),
_ = require('lodash'),
SDK = require('postman-collection'),
helper = require('./helper.js');
helper = require('./helper.js'),

// This is the default collection name if one can't be inferred from the RAML 1.0 spec
COLLECTION_NAME = 'Converted from RAML 1.0';

/**
* Used to convert array to a map
Expand Down Expand Up @@ -35,12 +38,12 @@ var converter = {
let collection = new SDK.Collection(),
ramlAPI = raml.parseRAMLSync(ramlString),
ramlJSON = ramlAPI.toJSON(),
baseUrl = new SDK.Variable(),
convertedBaseUrl,
info = {
title: ramlJSON.title || '',
documentation: ramlJSON.documentation || '',
description: ramlJSON.description || '',
version: ramlJSON.version || ''
title: _.get(ramlJSON, 'title', COLLECTION_NAME),
documentation: _.get(ramlJSON, 'documentation', ''),
description: _.get(ramlJSON, 'description', ''),
version: _.get(ramlJSON, 'version', '')
},
RootParameters = {
mediaType: ramlJSON.mediaType,
Expand All @@ -49,19 +52,33 @@ var converter = {
baseUri: ramlJSON.baseUri,
baseUriParameters: ramlJSON.baseUriParameters,
securitySchemes: '',
securedBy: ramlJSON.securedBy || ''
securedBy: _.get(ramlJSON, 'securedBy', '')
};

collection = helper.setCollectionInfo(info, collection);
ramlJSON.types && (RootParameters.types = arrayToMap(ramlJSON.types));
ramlJSON.traits && (RootParameters.traits = arrayToMap(ramlJSON.traits));
ramlJSON.securitySchemes && (RootParameters.securitySchemes = arrayToMap(ramlJSON.securitySchemes));
baseUrl.key = 'baseUrl';
baseUrl.value = helper.addParametersToUrl(ramlJSON.baseUri, ramlJSON.baseUriParameters);
collection.variables.add(baseUrl);

// Returns object containing url and all path variables with SDK compatible format
// Also adds {{baseUrl}} collection variable
helper.convertToPmCollectionVariables(
ramlJSON.baseUriParameters,
'baseUrl',
ramlJSON.baseUri
).forEach((element) => {
collection.variables.add(element);
});

// convrtedBaseUrl is URL containing baseUrl in form of PM collection variable
convertedBaseUrl = new SDK.Variable({
key: 'baseUrl',
value: '{{baseUrl}}',
type: 'string'
});

ramlJSON.resources && ramlJSON.resources.forEach(function (resource) {
collection.items.add(helper.convertResources(baseUrl, resource, RootParameters));
collection.items.add(helper.convertResources(convertedBaseUrl, resource, RootParameters));
});

return cb(null, {
Expand Down
139 changes: 124 additions & 15 deletions lib/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,50 @@ helper = {

collection.name = info.title;
collection.version = info.version;
collection.description = info.documentation.concat(info.description);
collection.description = helper.convertDescription(info.description, info.documentation);

return collection;
},

/**
* RAML 1.0 supports documentation of schema which supports Markdown.
* This function converts it into postman description with some Markdown Formatting.
* https://github.com/raml-org/raml-spec/blob/master/versions/raml-10/raml-10.md#user-documentation
*
* @param {String} ramlDescription - Description of an schema
* @param {Array} ramlDocumentation - Documentation of schema
*
* @returns {String} - Postman collection description.
*/
convertDescription: function(ramlDescription, ramlDocumentation) {
let description;

if (ramlDocumentation) {
description = '# Description\n\n' + ramlDescription + '\n\n';
description += '# Documentation\n\n';

// Handle converted description for invalid documentation
if (_.isArray(ramlDocumentation)) {
_.forEach(ramlDocumentation, (value) => {
if (value.title && value.content) {
description += `## ${value.title}\n\n${value.content}\n\n`;
}
else {
description += 'Invalid Documentaion key-value pair\n';
}
});
}
else {
description += _.toString(ramlDocumentation);
}
}
else {
description = ramlDescription;
}

return description;
},

/**
*
* Used to convert a raml json header into postman sdk header object
Expand Down Expand Up @@ -283,21 +322,69 @@ helper = {
return auth;
},

/**
* Converts the neccessary root level variables to the
* something that can be added to the collection
*
* @param {Array} variablesToAdd - Object containing the root level variables at the root/path-item level
* @param {String} keyName - an additional key to add the baseUrl to the variable list
* @param {String} baseUrl - URL from the baseUrl object
* @returns {Array} modified collection variable array
*/
convertToPmCollectionVariables: function(variablesToAdd, keyName, baseUrl = '') {
var variables = [],
convertedBaseUrl = baseUrl;

if (variablesToAdd) {
_.forOwn(variablesToAdd, (value, key) => {
// 'version' is reserved base URI parameter for RAML 1.0, value of it recieved in enum so special handling
if (key === 'version') {
variables.push(new SDK.Variable({
id: key,
value: _.get(value, 'enum[0]', ''),
description: value.description || 'This is version of API schema.'
}));
}
else {
variables.push(new SDK.Variable({
id: key,
value: value.default || '',
description: value.description + (value.enum ? ' (is one of ' + value.enum + ')' : '')
}));
}
// replace base url variables according to postman variable identification syntax
convertedBaseUrl = convertedBaseUrl.replace('{' + key + '}', '{{' + key + '}}');
});
}
if (keyName) {
variables.push(new SDK.Variable({
id: keyName,
value: convertedBaseUrl,
type: 'string'
}));
}

return variables;
},

/**
*
* Used to convert raml method json to a postman sdk item object
*
* @param {Object} method - raml method in json format
* @param {String} url - url of the raml request
* @param {Object} globalParameters - Object with parameters given at root level of raml spec
* @param {Array} pathVariables - Optional path variables array to add value/description of path varibles in url
*
* @returns {Object} item - postman sdk item object
*/
convertMethod: function(method, url, globalParameters) {
convertMethod: function(method, url, globalParameters, pathVariables) {
let item = new SDK.Item(),
request = new SDK.Request(),
requestUrl = new SDK.Url(),
mediaType = globalParameters.mediaType || 'application/json',
securedBy = method.securedBy || globalParameters.securedBy;
securedBy = method.securedBy || globalParameters.securedBy,
requestName = _.get(method, 'displayName', url.replace('{{baseUrl}}', ''));

method.is && (method = addTraitsToMethod(method, globalParameters.traits));
if (method.queryParameters) {
Expand All @@ -306,18 +393,25 @@ helper = {
if (method.queryString) {
url = url.concat(helper.constructQueryString(method.queryString, globalParameters.types));
}
method.description && (item.description = (method.description));
method.description && (request.description = method.description);
method.body && (request.body = new SDK.RequestBody({
mode: 'raw',
raw: JSON.stringify(helper.convertBody(method.body, globalParameters.types, request))
})) && request.headers.add(helper.getContentTypeHeader(mediaType));
method.responses && (item.responses.add(helper.convertResponse(method.responses, globalParameters.types)));
securedBy && (request.auth = helper.convertSecurityScheme(securedBy[0], globalParameters.securitySchemes));
request.url = url;
request.method = method.method;
requestUrl.update(url);

// Add path variables of url to request
if (pathVariables) {
requestUrl.variables = pathVariables;
}
request.url = requestUrl;
request.method = _.toUpper(method.method);
_.forEach(method.headers, (header) => {
request.headers.add(helper.convertHeader(header, globalParameters.types));
});
item.name = requestName;
item.request = request;

return item;
Expand All @@ -331,16 +425,24 @@ helper = {
* @param {Object} params - raml url parameters object
* @param {Object} types - raml types map
*
* @returns {string} url - postman url string
* @returns {Object} contains url - postman url string, variables - path variable array
*/
addParametersToUrl: function(baseUrl, params, types) {
let paramToReplace,
paramToBeReplaced,
variables = [],
url = baseUrl,
value,
type;

_.forEach(params, (param, key) => {
variables.push({
key: key,
value: param.default || '',
description: (param.description || '') + (param.enum ?
' (This can only be one of ' + param.enum.toString() + ')' : '')
});

paramToReplace = key;
value = param.default || param.example;
if (param.type[0] !== 'string' &&
Expand All @@ -349,12 +451,14 @@ helper = {
type = param.type[0];
value = types[type].default || types[type].example || value;
}
value && (paramToReplace = `${key}=${value}/`);
paramToBeReplaced = '{' + key + '}';
url = url.replace(paramToBeReplaced, ':' + paramToReplace);
});

return url;
return {
url: url,
variables: variables
};
},

/**
Expand All @@ -364,27 +468,32 @@ helper = {
* @param {string} baseUrl - base url string
* @param {String} res - raml resource json
* @param {Object} globalParameters - Object with parameters given at root level of raml spec
* @param {Array} pathVariables - Array with all path variables and it's value and decription.
*
* @returns {Object} folder - postman sdk ItemGroup object
*/
convertResources: function(baseUrl, res, globalParameters) {
convertResources: function(baseUrl, res, globalParameters, pathVariables = []) {
var folder = new SDK.ItemGroup(),
url;
url,
convertedUrlAndVars;

url = '{{' + baseUrl.key + '}}' +
helper.addParametersToUrl(res.displayName, res.uriParameters, globalParameters.types);
convertedUrlAndVars = helper.addParametersToUrl(res.relativeUri, res.uriParameters, globalParameters.types);
url = baseUrl.value + convertedUrlAndVars.url;
pathVariables = _.concat(pathVariables, convertedUrlAndVars.variables);

baseUrl.value = url;
res.displayName && (folder.name = res.displayName);
res.description && (folder.description = res.description);
res.is && res.methods.forEach(function (method) {
method.is = res.is;
});

res.methods && res.methods.forEach(function (method) {
folder.items.add(helper.convertMethod(method, url, globalParameters));
folder.items.add(helper.convertMethod(method, url, globalParameters, pathVariables));
});

res.resources && res.resources.forEach(function (resource) {
folder.items.add(helper.convertResources(baseUrl, resource, globalParameters));
folder.items.add(helper.convertResources(baseUrl, resource, globalParameters, pathVariables));
});

return folder;
Expand Down
41 changes: 35 additions & 6 deletions test/fixtures/valid-raml/ramlSpecBasicCollection.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,20 @@
}
],
"event": [],
"name": "/users/search",
"request": {
"url": "{{baseUrl}}/search",
"method": "get",
"url": {
"path": [
"users",
"search"
],
"host": [
"{{baseUrl}}"
],
"query": [],
"variables": []
},
"method": "GET",
"auth": {
"type": "basic",
"description": {
Expand All @@ -39,8 +50,19 @@
{
"response": [],
"event": [],
"name": "/users/search",
"request": {
"url": "{{baseUrl}}/search",
"url": {
"path": [
"users",
"search"
],
"host": [
"{{baseUrl}}"
],
"query": [],
"variables": []
},
"header": [
{
"key": "Content-Type",
Expand All @@ -55,7 +77,7 @@
"value": "OtherExample"
}
],
"method": "post",
"method": "POST",
"body": {
"mode": "raw",
"raw": "{\"firstname\":\"someName\",\"lastname\":\"someLastName\",\"age\":10}"
Expand All @@ -81,9 +103,16 @@
"event": [],
"variable": [
{
"description": {
"content": "This is version of API schema.",
"type": "text/plain"
},
"type": "any",
"value": "https://api.BasicRamlAPI.com/:version",
"key": "baseUrl"
"value": "v3"
},
{
"type": "string",
"value": "https://api.BasicRamlAPI.com/{{version}}"
}
],
"info": {
Expand Down
12 changes: 12 additions & 0 deletions test/fixtures/valid-raml/ramlSpecNameAndDesc.raml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#%RAML 1.0
title: The Naming And Description One
version: v5
baseUri: https://name.me/{version}
/users:
displayName: Folder named /users
get:
description: Description of /users GET req
/teams:
description: Description of Folder named /teams
get:
displayName: GET req of /admins
Loading