ruby.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. "use strict";
  2. var _ = require('../../lodash'), parseBody = require('./util/parseBody'), sanitize = require('./util/sanitize').sanitize, sanitizeOptions = require('./util/sanitize').sanitizeOptions, addFormParam = require('./util/sanitize').addFormParam, self;
  3. /**
  4. * Used to parse the request headers
  5. *
  6. * @param {Object} headers - postman SDK-request object
  7. * @returns {String} - request headers in the desired format
  8. */
  9. function parseHeaders(headers) {
  10. var headerSnippet = '';
  11. if (!_.isEmpty(headers)) {
  12. _.forEach(headers, function (value, key) {
  13. if (Array.isArray(value)) {
  14. var headerValues = [];
  15. _.forEach(value, (singleValue) => {
  16. headerValues.push(`"${sanitize(singleValue, 'header')}"`);
  17. });
  18. headerSnippet += `request["${sanitize(key, 'header', true)}"] = [${headerValues.join(', ')}]\n`;
  19. }
  20. else {
  21. headerSnippet += `request["${sanitize(key, 'header', true)}"] = "${sanitize(value, 'header')}"\n`;
  22. }
  23. });
  24. }
  25. return headerSnippet;
  26. }
  27. self = module.exports = {
  28. /**
  29. * Used to return options which are specific to a particular plugin
  30. *
  31. * @returns {Array}
  32. */
  33. getOptions: function () {
  34. return [{
  35. name: 'Set indentation count',
  36. id: 'indentCount',
  37. type: 'positiveInteger',
  38. default: 2,
  39. description: 'Set the number of indentation characters to add per code level'
  40. },
  41. {
  42. name: 'Set indentation type',
  43. id: 'indentType',
  44. type: 'enum',
  45. availableOptions: ['Tab', 'Space'],
  46. default: 'Space',
  47. description: 'Select the character used to indent lines of code'
  48. },
  49. {
  50. name: 'Set request timeout',
  51. id: 'requestTimeout',
  52. type: 'positiveInteger',
  53. default: 0,
  54. description: 'Set number of milliseconds the request should wait for a response' +
  55. ' before timing out (use 0 for infinity)'
  56. },
  57. {
  58. name: 'Follow redirects',
  59. id: 'followRedirect',
  60. type: 'boolean',
  61. default: true,
  62. description: 'Automatically follow HTTP redirects'
  63. },
  64. {
  65. name: 'Trim request body fields',
  66. id: 'trimRequestBody',
  67. type: 'boolean',
  68. default: false,
  69. description: 'Remove white space and additional lines that may affect the server\'s response'
  70. }];
  71. },
  72. /**
  73. * Used to convert the postman sdk-request object in ruby request snippet
  74. *
  75. * @param {Object} request - postman SDK-request object
  76. * @param {Object} options
  77. * @param {String} options.indentType - type of indentation eg: Space / Tab (default: Space)
  78. * @param {Number} options.indentCount - frequency of indent (default: 4 for indentType: Space,
  79. default: 1 for indentType: Tab)
  80. * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out
  81. (default: 0 -> never bail out)
  82. * @param {Boolean} options.trimRequestBody : whether to trim request body fields (default: false)
  83. * @param {Boolean} options.followRedirect : whether to allow redirects of a request
  84. * @param {Function} callback - function with parameters (error, snippet)
  85. */
  86. convert: function (request, options, callback) {
  87. var snippet = '', indentation = '', identity = '', headerSnippet = '', methods = ['GET', 'POST', 'HEAD', 'DELETE', 'PATCH', 'PROPFIND',
  88. 'PROPPATCH', 'PUT', 'OPTIONS', 'COPY', 'LOCK', 'UNLOCK', 'MOVE', 'TRACE'];
  89. if (_.isFunction(options)) {
  90. callback = options;
  91. options = null;
  92. }
  93. else if (!_.isFunction(callback)) {
  94. throw new Error('Ruby~convert: Callback is not a function');
  95. }
  96. options = sanitizeOptions(options, self.getOptions());
  97. identity = options.indentType === 'Tab' ? '\t' : ' ';
  98. indentation = identity.repeat(options.indentCount);
  99. // concatenation and making up the final string
  100. snippet = 'require "uri"\n';
  101. snippet += 'require "net/http"\n\n';
  102. if (!_.includes(methods, request.method)) {
  103. snippet += `class Net::HTTP::${_.capitalize(request.method)} < Net::HTTPRequest\n`;
  104. snippet += `${indentation}METHOD = "${request.method}"\n`;
  105. snippet += `${indentation}REQUEST_HAS_BODY = ${!_.isEmpty(request.body)}\n`;
  106. snippet += `${indentation}RESPONSE_HAS_BODY = true\n`;
  107. snippet += 'end\n\n';
  108. }
  109. snippet += `url = URI("${sanitize(request.url.toString(), 'url')}")\n\n`;
  110. if (sanitize(request.url.toString(), 'url').startsWith('https')) {
  111. snippet += 'https = Net::HTTP.new(url.host, url.port)\n';
  112. snippet += 'https.use_ssl = true\n\n';
  113. if (options.requestTimeout) {
  114. snippet += `https.read_timeout = ${Math.ceil(options.requestTimeout / 1000)}\n`;
  115. }
  116. snippet += `request = Net::HTTP::${_.capitalize(request.method)}.new(url)\n`;
  117. if (request.body && !request.headers.has('Content-Type')) {
  118. if (request.body.mode === 'file') {
  119. request.addHeader({
  120. key: 'Content-Type',
  121. value: 'text/plain'
  122. });
  123. }
  124. else if (request.body.mode === 'graphql') {
  125. request.addHeader({
  126. key: 'Content-Type',
  127. value: 'application/json'
  128. });
  129. }
  130. }
  131. headerSnippet = parseHeaders(request.getHeaders({ enabled: true }));
  132. if (headerSnippet !== '') {
  133. snippet += headerSnippet;
  134. }
  135. // The following code handles multiple files in the same formdata param.
  136. // It removes the form data params where the src property is an array of filepath strings
  137. // Splits that array into different form data params with src set as a single filepath string
  138. if (request.body && request.body.mode === 'formdata') {
  139. let formdata = request.body.formdata, formdataArray = [];
  140. formdata.members.forEach((param) => {
  141. let key = param.key, type = param.type, disabled = param.disabled, contentType = param.contentType;
  142. // check if type is file or text
  143. if (type === 'file') {
  144. // if src is not of type string we check for array(multiple files)
  145. if (typeof param.src !== 'string') {
  146. // if src is an array(not empty), iterate over it and add files as separate form fields
  147. if (Array.isArray(param.src) && param.src.length) {
  148. param.src.forEach((filePath) => {
  149. addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
  150. });
  151. }
  152. // if src is not an array or string, or is an empty array, add a placeholder for file path(no files case)
  153. else {
  154. addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
  155. }
  156. }
  157. // if src is string, directly add the param with src as filepath
  158. else {
  159. addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
  160. }
  161. }
  162. // if type is text, directly add it to formdata array
  163. else {
  164. addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
  165. }
  166. });
  167. request.body.update({
  168. mode: 'formdata',
  169. formdata: formdataArray
  170. });
  171. }
  172. snippet += `${parseBody(request.toJSON(), options.trimRequestBody)}\n`;
  173. snippet += 'response = https.request(request)\n';
  174. snippet += 'puts response.read_body\n';
  175. }
  176. else {
  177. snippet += 'http = Net::HTTP.new(url.host, url.port);\n';
  178. if (options.requestTimeout) {
  179. snippet += `http.read_timeout = ${Math.ceil(options.requestTimeout / 1000)}\n`;
  180. }
  181. snippet += `request = Net::HTTP::${_.capitalize(request.method)}.new(url)\n`;
  182. if (request.body && !request.headers.has('Content-Type')) {
  183. if (request.body.mode === 'file') {
  184. request.addHeader({
  185. key: 'Content-Type',
  186. value: 'text/plain'
  187. });
  188. }
  189. else if (request.body.mode === 'graphql') {
  190. request.addHeader({
  191. key: 'Content-Type',
  192. value: 'application/json'
  193. });
  194. }
  195. }
  196. headerSnippet = parseHeaders(request.getHeaders({ enabled: true }));
  197. if (headerSnippet !== '') {
  198. snippet += headerSnippet;
  199. }
  200. snippet += `${parseBody(request.toJSON(), options.trimRequestBody)}\n`;
  201. snippet += 'response = http.request(request)\n';
  202. snippet += 'puts response.read_body\n';
  203. }
  204. return callback(null, snippet);
  205. }
  206. };