postman.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals, absolute_import
  3. from time import time
  4. from uuid import uuid5, NAMESPACE_URL
  5. from six import iteritems
  6. from six.moves.urllib.parse import urlencode
  7. def clean(data):
  8. """Remove all keys where value is None"""
  9. return dict((k, v) for k, v in iteritems(data) if v is not None)
  10. DEFAULT_VARS = {
  11. "string": "",
  12. "integer": 0,
  13. "number": 0,
  14. }
  15. class Request(object):
  16. """Wraps a Swagger operation into a Postman Request"""
  17. def __init__(self, collection, path, params, method, operation):
  18. self.collection = collection
  19. self.path = path
  20. self.params = params
  21. self.method = method.upper()
  22. self.operation = operation
  23. @property
  24. def id(self):
  25. seed = str(" ".join((self.method, self.url)))
  26. return str(uuid5(self.collection.uuid, seed))
  27. @property
  28. def url(self):
  29. return self.collection.api.base_url.rstrip("/") + self.path
  30. @property
  31. def headers(self):
  32. headers = {}
  33. # Handle content-type
  34. if self.method != "GET":
  35. consumes = self.collection.api.__schema__.get("consumes", [])
  36. consumes = self.operation.get("consumes", consumes)
  37. if len(consumes):
  38. headers["Content-Type"] = consumes[-1]
  39. # Add all parameters headers
  40. for param in self.operation.get("parameters", []):
  41. if param["in"] == "header":
  42. headers[param["name"]] = param.get("default", "")
  43. # Add security headers if needed (global then local)
  44. for security in self.collection.api.__schema__.get("security", []):
  45. for key, header in iteritems(self.collection.apikeys):
  46. if key in security:
  47. headers[header] = ""
  48. for security in self.operation.get("security", []):
  49. for key, header in iteritems(self.collection.apikeys):
  50. if key in security:
  51. headers[header] = ""
  52. lines = [":".join(line) for line in iteritems(headers)]
  53. return "\n".join(lines)
  54. @property
  55. def folder(self):
  56. if "tags" not in self.operation or len(self.operation["tags"]) == 0:
  57. return
  58. tag = self.operation["tags"][0]
  59. for folder in self.collection.folders:
  60. if folder.tag == tag:
  61. return folder.id
  62. def as_dict(self, urlvars=False):
  63. url, variables = self.process_url(urlvars)
  64. return clean(
  65. {
  66. "id": self.id,
  67. "method": self.method,
  68. "name": self.operation["operationId"],
  69. "description": self.operation.get("summary"),
  70. "url": url,
  71. "headers": self.headers,
  72. "collectionId": self.collection.id,
  73. "folder": self.folder,
  74. "pathVariables": variables,
  75. "time": int(time()),
  76. }
  77. )
  78. def process_url(self, urlvars=False):
  79. url = self.url
  80. path_vars = {}
  81. url_vars = {}
  82. params = dict((p["name"], p) for p in self.params)
  83. params.update(
  84. dict((p["name"], p) for p in self.operation.get("parameters", []))
  85. )
  86. if not params:
  87. return url, None
  88. for name, param in iteritems(params):
  89. if param["in"] == "path":
  90. url = url.replace("{%s}" % name, ":%s" % name)
  91. path_vars[name] = DEFAULT_VARS.get(param["type"], "")
  92. elif param["in"] == "query" and urlvars:
  93. default = DEFAULT_VARS.get(param["type"], "")
  94. url_vars[name] = param.get("default", default)
  95. if url_vars:
  96. url = "?".join((url, urlencode(url_vars)))
  97. return url, path_vars
  98. class Folder(object):
  99. def __init__(self, collection, tag):
  100. self.collection = collection
  101. self.tag = tag["name"]
  102. self.description = tag["description"]
  103. @property
  104. def id(self):
  105. return str(uuid5(self.collection.uuid, str(self.tag)))
  106. @property
  107. def order(self):
  108. return [r.id for r in self.collection.requests if r.folder == self.id]
  109. def as_dict(self):
  110. return clean(
  111. {
  112. "id": self.id,
  113. "name": self.tag,
  114. "description": self.description,
  115. "order": self.order,
  116. "collectionId": self.collection.id,
  117. }
  118. )
  119. class PostmanCollectionV1(object):
  120. """Postman Collection (V1 format) serializer"""
  121. def __init__(self, api, swagger=False):
  122. self.api = api
  123. self.swagger = swagger
  124. @property
  125. def uuid(self):
  126. return uuid5(NAMESPACE_URL, self.api.base_url)
  127. @property
  128. def id(self):
  129. return str(self.uuid)
  130. @property
  131. def requests(self):
  132. if self.swagger:
  133. # First request is Swagger specifications
  134. yield Request(
  135. self,
  136. "/swagger.json",
  137. {},
  138. "get",
  139. {
  140. "operationId": "Swagger specifications",
  141. "summary": "The API Swagger specifications as JSON",
  142. },
  143. )
  144. # Then iter over API paths and methods
  145. for path, operations in iteritems(self.api.__schema__["paths"]):
  146. path_params = operations.get("parameters", [])
  147. for method, operation in iteritems(operations):
  148. if method != "parameters":
  149. yield Request(self, path, path_params, method, operation)
  150. @property
  151. def folders(self):
  152. for tag in self.api.__schema__["tags"]:
  153. yield Folder(self, tag)
  154. @property
  155. def apikeys(self):
  156. return dict(
  157. (name, secdef["name"])
  158. for name, secdef in iteritems(
  159. self.api.__schema__.get("securityDefinitions")
  160. )
  161. if secdef.get("in") == "header" and secdef.get("type") == "apiKey"
  162. )
  163. def as_dict(self, urlvars=False):
  164. return clean(
  165. {
  166. "id": self.id,
  167. "name": " ".join((self.api.title, self.api.version)),
  168. "description": self.api.description,
  169. "order": [r.id for r in self.requests if not r.folder],
  170. "requests": [r.as_dict(urlvars=urlvars) for r in self.requests],
  171. "folders": [f.as_dict() for f in self.folders],
  172. "timestamp": int(time()),
  173. }
  174. )