You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

448 lines
12 KiB

  1. // Copyright 2015 go-swagger maintainers
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package spec
  15. import (
  16. "bytes"
  17. "encoding/gob"
  18. "encoding/json"
  19. "fmt"
  20. "strconv"
  21. "github.com/go-openapi/jsonpointer"
  22. "github.com/go-openapi/swag"
  23. )
  24. // Swagger this is the root document object for the API specification.
  25. // It combines what previously was the Resource Listing and API Declaration (version 1.2 and earlier)
  26. // together into one document.
  27. //
  28. // For more information: http://goo.gl/8us55a#swagger-object-
  29. type Swagger struct {
  30. VendorExtensible
  31. SwaggerProps
  32. }
  33. // JSONLookup look up a value by the json property name
  34. func (s Swagger) JSONLookup(token string) (interface{}, error) {
  35. if ex, ok := s.Extensions[token]; ok {
  36. return &ex, nil
  37. }
  38. r, _, err := jsonpointer.GetForToken(s.SwaggerProps, token)
  39. return r, err
  40. }
  41. // MarshalJSON marshals this swagger structure to json
  42. func (s Swagger) MarshalJSON() ([]byte, error) {
  43. b1, err := json.Marshal(s.SwaggerProps)
  44. if err != nil {
  45. return nil, err
  46. }
  47. b2, err := json.Marshal(s.VendorExtensible)
  48. if err != nil {
  49. return nil, err
  50. }
  51. return swag.ConcatJSON(b1, b2), nil
  52. }
  53. // UnmarshalJSON unmarshals a swagger spec from json
  54. func (s *Swagger) UnmarshalJSON(data []byte) error {
  55. var sw Swagger
  56. if err := json.Unmarshal(data, &sw.SwaggerProps); err != nil {
  57. return err
  58. }
  59. if err := json.Unmarshal(data, &sw.VendorExtensible); err != nil {
  60. return err
  61. }
  62. *s = sw
  63. return nil
  64. }
  65. // GobEncode provides a safe gob encoder for Swagger, including extensions
  66. func (s Swagger) GobEncode() ([]byte, error) {
  67. var b bytes.Buffer
  68. raw := struct {
  69. Props SwaggerProps
  70. Ext VendorExtensible
  71. }{
  72. Props: s.SwaggerProps,
  73. Ext: s.VendorExtensible,
  74. }
  75. err := gob.NewEncoder(&b).Encode(raw)
  76. return b.Bytes(), err
  77. }
  78. // GobDecode provides a safe gob decoder for Swagger, including extensions
  79. func (s *Swagger) GobDecode(b []byte) error {
  80. var raw struct {
  81. Props SwaggerProps
  82. Ext VendorExtensible
  83. }
  84. buf := bytes.NewBuffer(b)
  85. err := gob.NewDecoder(buf).Decode(&raw)
  86. if err != nil {
  87. return err
  88. }
  89. s.SwaggerProps = raw.Props
  90. s.VendorExtensible = raw.Ext
  91. return nil
  92. }
  93. // SwaggerProps captures the top-level properties of an Api specification
  94. //
  95. // NOTE: validation rules
  96. // - the scheme, when present must be from [http, https, ws, wss]
  97. // - BasePath must start with a leading "/"
  98. // - Paths is required
  99. type SwaggerProps struct {
  100. ID string `json:"id,omitempty"`
  101. Consumes []string `json:"consumes,omitempty"`
  102. Produces []string `json:"produces,omitempty"`
  103. Schemes []string `json:"schemes,omitempty"`
  104. Swagger string `json:"swagger,omitempty"`
  105. Info *Info `json:"info,omitempty"`
  106. Host string `json:"host,omitempty"`
  107. BasePath string `json:"basePath,omitempty"`
  108. Paths *Paths `json:"paths"`
  109. Definitions Definitions `json:"definitions,omitempty"`
  110. Parameters map[string]Parameter `json:"parameters,omitempty"`
  111. Responses map[string]Response `json:"responses,omitempty"`
  112. SecurityDefinitions SecurityDefinitions `json:"securityDefinitions,omitempty"`
  113. Security []map[string][]string `json:"security,omitempty"`
  114. Tags []Tag `json:"tags,omitempty"`
  115. ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
  116. }
  117. type swaggerPropsAlias SwaggerProps
  118. type gobSwaggerPropsAlias struct {
  119. Security []map[string]struct {
  120. List []string
  121. Pad bool
  122. }
  123. Alias *swaggerPropsAlias
  124. SecurityIsEmpty bool
  125. }
  126. // GobEncode provides a safe gob encoder for SwaggerProps, including empty security requirements
  127. func (o SwaggerProps) GobEncode() ([]byte, error) {
  128. raw := gobSwaggerPropsAlias{
  129. Alias: (*swaggerPropsAlias)(&o),
  130. }
  131. var b bytes.Buffer
  132. if o.Security == nil {
  133. // nil security requirement
  134. err := gob.NewEncoder(&b).Encode(raw)
  135. return b.Bytes(), err
  136. }
  137. if len(o.Security) == 0 {
  138. // empty, but non-nil security requirement
  139. raw.SecurityIsEmpty = true
  140. raw.Alias.Security = nil
  141. err := gob.NewEncoder(&b).Encode(raw)
  142. return b.Bytes(), err
  143. }
  144. raw.Security = make([]map[string]struct {
  145. List []string
  146. Pad bool
  147. }, 0, len(o.Security))
  148. for _, req := range o.Security {
  149. v := make(map[string]struct {
  150. List []string
  151. Pad bool
  152. }, len(req))
  153. for k, val := range req {
  154. v[k] = struct {
  155. List []string
  156. Pad bool
  157. }{
  158. List: val,
  159. }
  160. }
  161. raw.Security = append(raw.Security, v)
  162. }
  163. err := gob.NewEncoder(&b).Encode(raw)
  164. return b.Bytes(), err
  165. }
  166. // GobDecode provides a safe gob decoder for SwaggerProps, including empty security requirements
  167. func (o *SwaggerProps) GobDecode(b []byte) error {
  168. var raw gobSwaggerPropsAlias
  169. buf := bytes.NewBuffer(b)
  170. err := gob.NewDecoder(buf).Decode(&raw)
  171. if err != nil {
  172. return err
  173. }
  174. if raw.Alias == nil {
  175. return nil
  176. }
  177. switch {
  178. case raw.SecurityIsEmpty:
  179. // empty, but non-nil security requirement
  180. raw.Alias.Security = []map[string][]string{}
  181. case len(raw.Alias.Security) == 0:
  182. // nil security requirement
  183. raw.Alias.Security = nil
  184. default:
  185. raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security))
  186. for _, req := range raw.Security {
  187. v := make(map[string][]string, len(req))
  188. for k, val := range req {
  189. v[k] = make([]string, 0, len(val.List))
  190. v[k] = append(v[k], val.List...)
  191. }
  192. raw.Alias.Security = append(raw.Alias.Security, v)
  193. }
  194. }
  195. *o = *(*SwaggerProps)(raw.Alias)
  196. return nil
  197. }
  198. // Dependencies represent a dependencies property
  199. type Dependencies map[string]SchemaOrStringArray
  200. // SchemaOrBool represents a schema or boolean value, is biased towards true for the boolean property
  201. type SchemaOrBool struct {
  202. Allows bool
  203. Schema *Schema
  204. }
  205. // JSONLookup implements an interface to customize json pointer lookup
  206. func (s SchemaOrBool) JSONLookup(token string) (interface{}, error) {
  207. if token == "allows" {
  208. return s.Allows, nil
  209. }
  210. r, _, err := jsonpointer.GetForToken(s.Schema, token)
  211. return r, err
  212. }
  213. var jsTrue = []byte("true")
  214. var jsFalse = []byte("false")
  215. // MarshalJSON convert this object to JSON
  216. func (s SchemaOrBool) MarshalJSON() ([]byte, error) {
  217. if s.Schema != nil {
  218. return json.Marshal(s.Schema)
  219. }
  220. if s.Schema == nil && !s.Allows {
  221. return jsFalse, nil
  222. }
  223. return jsTrue, nil
  224. }
  225. // UnmarshalJSON converts this bool or schema object from a JSON structure
  226. func (s *SchemaOrBool) UnmarshalJSON(data []byte) error {
  227. var nw SchemaOrBool
  228. if len(data) >= 4 {
  229. if data[0] == '{' {
  230. var sch Schema
  231. if err := json.Unmarshal(data, &sch); err != nil {
  232. return err
  233. }
  234. nw.Schema = &sch
  235. }
  236. nw.Allows = !(data[0] == 'f' && data[1] == 'a' && data[2] == 'l' && data[3] == 's' && data[4] == 'e')
  237. }
  238. *s = nw
  239. return nil
  240. }
  241. // SchemaOrStringArray represents a schema or a string array
  242. type SchemaOrStringArray struct {
  243. Schema *Schema
  244. Property []string
  245. }
  246. // JSONLookup implements an interface to customize json pointer lookup
  247. func (s SchemaOrStringArray) JSONLookup(token string) (interface{}, error) {
  248. r, _, err := jsonpointer.GetForToken(s.Schema, token)
  249. return r, err
  250. }
  251. // MarshalJSON converts this schema object or array into JSON structure
  252. func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) {
  253. if len(s.Property) > 0 {
  254. return json.Marshal(s.Property)
  255. }
  256. if s.Schema != nil {
  257. return json.Marshal(s.Schema)
  258. }
  259. return []byte("null"), nil
  260. }
  261. // UnmarshalJSON converts this schema object or array from a JSON structure
  262. func (s *SchemaOrStringArray) UnmarshalJSON(data []byte) error {
  263. var first byte
  264. if len(data) > 1 {
  265. first = data[0]
  266. }
  267. var nw SchemaOrStringArray
  268. if first == '{' {
  269. var sch Schema
  270. if err := json.Unmarshal(data, &sch); err != nil {
  271. return err
  272. }
  273. nw.Schema = &sch
  274. }
  275. if first == '[' {
  276. if err := json.Unmarshal(data, &nw.Property); err != nil {
  277. return err
  278. }
  279. }
  280. *s = nw
  281. return nil
  282. }
  283. // Definitions contains the models explicitly defined in this spec
  284. // An object to hold data types that can be consumed and produced by operations.
  285. // These data types can be primitives, arrays or models.
  286. //
  287. // For more information: http://goo.gl/8us55a#definitionsObject
  288. type Definitions map[string]Schema
  289. // SecurityDefinitions a declaration of the security schemes available to be used in the specification.
  290. // This does not enforce the security schemes on the operations and only serves to provide
  291. // the relevant details for each scheme.
  292. //
  293. // For more information: http://goo.gl/8us55a#securityDefinitionsObject
  294. type SecurityDefinitions map[string]*SecurityScheme
  295. // StringOrArray represents a value that can either be a string
  296. // or an array of strings. Mainly here for serialization purposes
  297. type StringOrArray []string
  298. // Contains returns true when the value is contained in the slice
  299. func (s StringOrArray) Contains(value string) bool {
  300. for _, str := range s {
  301. if str == value {
  302. return true
  303. }
  304. }
  305. return false
  306. }
  307. // JSONLookup implements an interface to customize json pointer lookup
  308. func (s SchemaOrArray) JSONLookup(token string) (interface{}, error) {
  309. if _, err := strconv.Atoi(token); err == nil {
  310. r, _, err := jsonpointer.GetForToken(s.Schemas, token)
  311. return r, err
  312. }
  313. r, _, err := jsonpointer.GetForToken(s.Schema, token)
  314. return r, err
  315. }
  316. // UnmarshalJSON unmarshals this string or array object from a JSON array or JSON string
  317. func (s *StringOrArray) UnmarshalJSON(data []byte) error {
  318. var first byte
  319. if len(data) > 1 {
  320. first = data[0]
  321. }
  322. if first == '[' {
  323. var parsed []string
  324. if err := json.Unmarshal(data, &parsed); err != nil {
  325. return err
  326. }
  327. *s = StringOrArray(parsed)
  328. return nil
  329. }
  330. var single interface{}
  331. if err := json.Unmarshal(data, &single); err != nil {
  332. return err
  333. }
  334. if single == nil {
  335. return nil
  336. }
  337. switch v := single.(type) {
  338. case string:
  339. *s = StringOrArray([]string{v})
  340. return nil
  341. default:
  342. return fmt.Errorf("only string or array is allowed, not %T", single)
  343. }
  344. }
  345. // MarshalJSON converts this string or array to a JSON array or JSON string
  346. func (s StringOrArray) MarshalJSON() ([]byte, error) {
  347. if len(s) == 1 {
  348. return json.Marshal([]string(s)[0])
  349. }
  350. return json.Marshal([]string(s))
  351. }
  352. // SchemaOrArray represents a value that can either be a Schema
  353. // or an array of Schema. Mainly here for serialization purposes
  354. type SchemaOrArray struct {
  355. Schema *Schema
  356. Schemas []Schema
  357. }
  358. // Len returns the number of schemas in this property
  359. func (s SchemaOrArray) Len() int {
  360. if s.Schema != nil {
  361. return 1
  362. }
  363. return len(s.Schemas)
  364. }
  365. // ContainsType returns true when one of the schemas is of the specified type
  366. func (s *SchemaOrArray) ContainsType(name string) bool {
  367. if s.Schema != nil {
  368. return s.Schema.Type != nil && s.Schema.Type.Contains(name)
  369. }
  370. return false
  371. }
  372. // MarshalJSON converts this schema object or array into JSON structure
  373. func (s SchemaOrArray) MarshalJSON() ([]byte, error) {
  374. if len(s.Schemas) > 0 {
  375. return json.Marshal(s.Schemas)
  376. }
  377. return json.Marshal(s.Schema)
  378. }
  379. // UnmarshalJSON converts this schema object or array from a JSON structure
  380. func (s *SchemaOrArray) UnmarshalJSON(data []byte) error {
  381. var nw SchemaOrArray
  382. var first byte
  383. if len(data) > 1 {
  384. first = data[0]
  385. }
  386. if first == '{' {
  387. var sch Schema
  388. if err := json.Unmarshal(data, &sch); err != nil {
  389. return err
  390. }
  391. nw.Schema = &sch
  392. }
  393. if first == '[' {
  394. if err := json.Unmarshal(data, &nw.Schemas); err != nil {
  395. return err
  396. }
  397. }
  398. *s = nw
  399. return nil
  400. }
  401. // vim:set ft=go noet sts=2 sw=2 ts=2: