request-body.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. "use strict";
  2. var _ = require('../../lodash'), PropertyBase = require('./property-base').PropertyBase, PropertyList = require('./property-list').PropertyList, QueryParam = require('./query-param').QueryParam, FormParam = require('./form-param').FormParam, EMPTY = '', RequestBody;
  3. /**
  4. * @typedef RequestBody.definition
  5. * @property {String} mode
  6. * @property {String} raw
  7. * @property {String} file
  8. * @property {Object} graphql
  9. * @property {Object[]} formdata
  10. * @property {Object[]|String} urlencoded
  11. */
  12. _.inherit((
  13. /**
  14. * RequestBody holds data related to the request body. By default, it provides a nice wrapper for url-encoded,
  15. * form-data, and raw types of request bodies.
  16. *
  17. * @constructor
  18. * @extends {PropertyBase}
  19. *
  20. * @param {Object} options
  21. */
  22. RequestBody = function PostmanRequestBody(options) {
  23. // this constructor is intended to inherit and as such the super constructor is required to be executed
  24. RequestBody.super_.apply(this, arguments);
  25. if (!options) {
  26. return;
  27. } // in case definition object is missing, there is no point moving forward
  28. this.update(options);
  29. }), PropertyBase);
  30. _.assign(RequestBody.prototype, /** @lends RequestBody.prototype */ {
  31. /**
  32. * Set the content of this request data
  33. *
  34. * @param {Object} options
  35. */
  36. update: function (options) {
  37. _.isString(options) && (options = { mode: 'raw', raw: options });
  38. if (!options.mode) {
  39. return;
  40. } // need a valid mode @todo raise error?
  41. var mode = RequestBody.MODES[options.mode.toString().toLowerCase()] || RequestBody.MODES.raw, urlencoded = options.urlencoded, formdata = options.formdata, graphql = options.graphql, file = options.file, raw = options.raw;
  42. // Handle URL Encoded data
  43. if (options.urlencoded) {
  44. _.isString(options.urlencoded) && (urlencoded = QueryParam.parse(options.urlencoded));
  45. // @todo: The fallback in the ternary expression will never be hit, as urlencoded points to
  46. // @todo: options.urlencoded
  47. urlencoded = urlencoded ? new PropertyList(QueryParam, this, urlencoded) :
  48. new PropertyList(QueryParam, this, []);
  49. }
  50. // Handle Form data
  51. if (options.formdata) {
  52. // @todo: The fallback in the ternary expression will never be hit, as formdata points to
  53. // @todo: options.formdata
  54. formdata = formdata ? new PropertyList(FormParam, this, options.formdata) :
  55. new PropertyList(FormParam, this, []);
  56. }
  57. // Handle GraphQL data
  58. if (options.graphql) {
  59. graphql = {
  60. query: graphql.query,
  61. operationName: graphql.operationName,
  62. variables: graphql.variables
  63. };
  64. }
  65. _.isString(options.file) && (file = { src: file });
  66. // If mode is raw but options does not give raw content, set it to empty string
  67. (mode === RequestBody.MODES.raw && !raw) && (raw = '');
  68. // If mode is urlencoded but options does not provide any content, set it to an empty property list
  69. (mode === RequestBody.MODES.urlencoded && !urlencoded) && (urlencoded = new PropertyList(QueryParam, this, []));
  70. // If mode is formdata but options does not provide any content, set it to an empty property list
  71. (mode === RequestBody.MODES.formdata && !formdata) && (formdata = new PropertyList(FormParam, this, []));
  72. // If mode is graphql but options does not provide any content, set empty query
  73. (mode === RequestBody.MODES.graphql && !graphql) && (graphql = {});
  74. _.assign(this, /** @lends RequestBody.prototype */ {
  75. /**
  76. * Indicates the type of request data to use.
  77. *
  78. * @type {String}
  79. */
  80. mode: mode,
  81. /**
  82. * If the request has raw body data associated with it, the data is held in this field.
  83. *
  84. * @type {String}
  85. */
  86. raw: raw,
  87. /**
  88. * Any URL encoded body params go here.
  89. *
  90. * @type {PropertyList<QueryParam>}
  91. */
  92. urlencoded: urlencoded,
  93. /**
  94. * Form data parameters for this request are held in this field.
  95. *
  96. * @type {PropertyList<FormParam>}
  97. */
  98. formdata: formdata,
  99. /**
  100. * Holds a reference to a file which should be read as the RequestBody. It can be a file path (when used
  101. * with Node) or a unique ID (when used with the browser).
  102. *
  103. * @note The reference stored here should be resolved by a resolver function (which should be provided to
  104. * the Postman Runtime).
  105. */
  106. file: file,
  107. /**
  108. * If the request has raw graphql data associated with it, the data is held in this field.
  109. *
  110. * @type {Object}
  111. */
  112. graphql: graphql,
  113. /**
  114. * If the request has body Options associated with it, the data is held in this field.
  115. *
  116. * @type {Object}
  117. */
  118. options: _.isObject(options.options) ? options.options : undefined,
  119. /**
  120. * Indicates whether to include body in request or not.
  121. *
  122. * @type {Boolean}
  123. */
  124. disabled: options.disabled
  125. });
  126. },
  127. /**
  128. * Stringifies and returns the request body.
  129. *
  130. * @note FormData is not supported yet.
  131. * @returns {*}
  132. */
  133. toString: function () {
  134. // Formdata. Goodluck.
  135. if (this.mode === RequestBody.MODES.formdata || this.mode === RequestBody.MODES.file) {
  136. // @todo: implement this, check if we need to return undefined or something.
  137. return EMPTY;
  138. }
  139. if (this.mode === RequestBody.MODES.urlencoded) {
  140. return PropertyList.isPropertyList(this.urlencoded) ? QueryParam.unparse(this.urlencoded.all()) :
  141. ((this.urlencoded && _.isFunction(this.urlencoded.toString)) ? this.urlencoded.toString() : EMPTY);
  142. }
  143. if (this.mode === RequestBody.MODES.raw) {
  144. return (this.raw && _.isFunction(this.raw.toString)) ? this.raw.toString() : EMPTY;
  145. }
  146. return EMPTY;
  147. },
  148. /**
  149. * If the request body is set to a mode, but does not contain data, then we should not be sending it.
  150. *
  151. * @returns {Boolean}
  152. */
  153. isEmpty: function () {
  154. var mode = this.mode, data = mode && this[mode];
  155. // bail out if there's no data for the selected mode
  156. if (!data) {
  157. return true;
  158. }
  159. // Handle file mode
  160. // @note this is a legacy exception. ideally every individual data mode
  161. // in future would declare its "empty state".
  162. if (mode === RequestBody.MODES.file) {
  163. return !(data.src || data.content);
  164. }
  165. if (_.isString(data)) {
  166. return (data.length === 0);
  167. }
  168. if (_.isFunction(data.count)) { // handle for property lists
  169. return (data.count() === 0);
  170. }
  171. return _.isEmpty(data); // catch all for remaining data modes
  172. },
  173. /**
  174. * Convert the request body to JSON compatible plain object
  175. *
  176. * @returns {Object}
  177. */
  178. toJSON: function () {
  179. var obj = PropertyBase.toJSON(this);
  180. // make sure that file content is removed because it is non-serializable ReadStream
  181. _.unset(obj, 'file.content');
  182. return obj;
  183. }
  184. });
  185. _.assign(RequestBody, /** @lends RequestBody **/ {
  186. /**
  187. * Defines the name of this property for internal use.
  188. * @private
  189. * @readOnly
  190. * @type {String}
  191. */
  192. _postman_propertyName: 'RequestBody',
  193. /**
  194. * @enum {string} MODES
  195. */
  196. MODES: {
  197. file: 'file',
  198. formdata: 'formdata',
  199. graphql: 'graphql',
  200. raw: 'raw',
  201. urlencoded: 'urlencoded'
  202. }
  203. });
  204. module.exports = {
  205. RequestBody: RequestBody
  206. };