本站源代码
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

399 linhas
11KB

  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. "sort"
  20. "github.com/go-openapi/jsonpointer"
  21. "github.com/go-openapi/swag"
  22. )
  23. func init() {
  24. //gob.Register(map[string][]interface{}{})
  25. gob.Register(map[string]interface{}{})
  26. gob.Register([]interface{}{})
  27. }
  28. // OperationProps describes an operation
  29. //
  30. // NOTES:
  31. // - schemes, when present must be from [http, https, ws, wss]: see validate
  32. // - Security is handled as a special case: see MarshalJSON function
  33. type OperationProps struct {
  34. Description string `json:"description,omitempty"`
  35. Consumes []string `json:"consumes,omitempty"`
  36. Produces []string `json:"produces,omitempty"`
  37. Schemes []string `json:"schemes,omitempty"`
  38. Tags []string `json:"tags,omitempty"`
  39. Summary string `json:"summary,omitempty"`
  40. ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
  41. ID string `json:"operationId,omitempty"`
  42. Deprecated bool `json:"deprecated,omitempty"`
  43. Security []map[string][]string `json:"security,omitempty"`
  44. Parameters []Parameter `json:"parameters,omitempty"`
  45. Responses *Responses `json:"responses,omitempty"`
  46. }
  47. // MarshalJSON takes care of serializing operation properties to JSON
  48. //
  49. // We use a custom marhaller here to handle a special cases related to
  50. // the Security field. We need to preserve zero length slice
  51. // while omitting the field when the value is nil/unset.
  52. func (op OperationProps) MarshalJSON() ([]byte, error) {
  53. type Alias OperationProps
  54. if op.Security == nil {
  55. return json.Marshal(&struct {
  56. Security []map[string][]string `json:"security,omitempty"`
  57. *Alias
  58. }{
  59. Security: op.Security,
  60. Alias: (*Alias)(&op),
  61. })
  62. }
  63. return json.Marshal(&struct {
  64. Security []map[string][]string `json:"security"`
  65. *Alias
  66. }{
  67. Security: op.Security,
  68. Alias: (*Alias)(&op),
  69. })
  70. }
  71. // Operation describes a single API operation on a path.
  72. //
  73. // For more information: http://goo.gl/8us55a#operationObject
  74. type Operation struct {
  75. VendorExtensible
  76. OperationProps
  77. }
  78. // SuccessResponse gets a success response model
  79. func (o *Operation) SuccessResponse() (*Response, int, bool) {
  80. if o.Responses == nil {
  81. return nil, 0, false
  82. }
  83. responseCodes := make([]int, 0, len(o.Responses.StatusCodeResponses))
  84. for k := range o.Responses.StatusCodeResponses {
  85. if k >= 200 && k < 300 {
  86. responseCodes = append(responseCodes, k)
  87. }
  88. }
  89. if len(responseCodes) > 0 {
  90. sort.Ints(responseCodes)
  91. v := o.Responses.StatusCodeResponses[responseCodes[0]]
  92. return &v, responseCodes[0], true
  93. }
  94. return o.Responses.Default, 0, false
  95. }
  96. // JSONLookup look up a value by the json property name
  97. func (o Operation) JSONLookup(token string) (interface{}, error) {
  98. if ex, ok := o.Extensions[token]; ok {
  99. return &ex, nil
  100. }
  101. r, _, err := jsonpointer.GetForToken(o.OperationProps, token)
  102. return r, err
  103. }
  104. // UnmarshalJSON hydrates this items instance with the data from JSON
  105. func (o *Operation) UnmarshalJSON(data []byte) error {
  106. if err := json.Unmarshal(data, &o.OperationProps); err != nil {
  107. return err
  108. }
  109. return json.Unmarshal(data, &o.VendorExtensible)
  110. }
  111. // MarshalJSON converts this items object to JSON
  112. func (o Operation) MarshalJSON() ([]byte, error) {
  113. b1, err := json.Marshal(o.OperationProps)
  114. if err != nil {
  115. return nil, err
  116. }
  117. b2, err := json.Marshal(o.VendorExtensible)
  118. if err != nil {
  119. return nil, err
  120. }
  121. concated := swag.ConcatJSON(b1, b2)
  122. return concated, nil
  123. }
  124. // NewOperation creates a new operation instance.
  125. // It expects an ID as parameter but not passing an ID is also valid.
  126. func NewOperation(id string) *Operation {
  127. op := new(Operation)
  128. op.ID = id
  129. return op
  130. }
  131. // WithID sets the ID property on this operation, allows for chaining.
  132. func (o *Operation) WithID(id string) *Operation {
  133. o.ID = id
  134. return o
  135. }
  136. // WithDescription sets the description on this operation, allows for chaining
  137. func (o *Operation) WithDescription(description string) *Operation {
  138. o.Description = description
  139. return o
  140. }
  141. // WithSummary sets the summary on this operation, allows for chaining
  142. func (o *Operation) WithSummary(summary string) *Operation {
  143. o.Summary = summary
  144. return o
  145. }
  146. // WithExternalDocs sets/removes the external docs for/from this operation.
  147. // When you pass empty strings as params the external documents will be removed.
  148. // When you pass non-empty string as one value then those values will be used on the external docs object.
  149. // So when you pass a non-empty description, you should also pass the url and vice versa.
  150. func (o *Operation) WithExternalDocs(description, url string) *Operation {
  151. if description == "" && url == "" {
  152. o.ExternalDocs = nil
  153. return o
  154. }
  155. if o.ExternalDocs == nil {
  156. o.ExternalDocs = &ExternalDocumentation{}
  157. }
  158. o.ExternalDocs.Description = description
  159. o.ExternalDocs.URL = url
  160. return o
  161. }
  162. // Deprecate marks the operation as deprecated
  163. func (o *Operation) Deprecate() *Operation {
  164. o.Deprecated = true
  165. return o
  166. }
  167. // Undeprecate marks the operation as not deprected
  168. func (o *Operation) Undeprecate() *Operation {
  169. o.Deprecated = false
  170. return o
  171. }
  172. // WithConsumes adds media types for incoming body values
  173. func (o *Operation) WithConsumes(mediaTypes ...string) *Operation {
  174. o.Consumes = append(o.Consumes, mediaTypes...)
  175. return o
  176. }
  177. // WithProduces adds media types for outgoing body values
  178. func (o *Operation) WithProduces(mediaTypes ...string) *Operation {
  179. o.Produces = append(o.Produces, mediaTypes...)
  180. return o
  181. }
  182. // WithTags adds tags for this operation
  183. func (o *Operation) WithTags(tags ...string) *Operation {
  184. o.Tags = append(o.Tags, tags...)
  185. return o
  186. }
  187. // AddParam adds a parameter to this operation, when a parameter for that location
  188. // and with that name already exists it will be replaced
  189. func (o *Operation) AddParam(param *Parameter) *Operation {
  190. if param == nil {
  191. return o
  192. }
  193. for i, p := range o.Parameters {
  194. if p.Name == param.Name && p.In == param.In {
  195. params := append(o.Parameters[:i], *param)
  196. params = append(params, o.Parameters[i+1:]...)
  197. o.Parameters = params
  198. return o
  199. }
  200. }
  201. o.Parameters = append(o.Parameters, *param)
  202. return o
  203. }
  204. // RemoveParam removes a parameter from the operation
  205. func (o *Operation) RemoveParam(name, in string) *Operation {
  206. for i, p := range o.Parameters {
  207. if p.Name == name && p.In == in {
  208. o.Parameters = append(o.Parameters[:i], o.Parameters[i+1:]...)
  209. return o
  210. }
  211. }
  212. return o
  213. }
  214. // SecuredWith adds a security scope to this operation.
  215. func (o *Operation) SecuredWith(name string, scopes ...string) *Operation {
  216. o.Security = append(o.Security, map[string][]string{name: scopes})
  217. return o
  218. }
  219. // WithDefaultResponse adds a default response to the operation.
  220. // Passing a nil value will remove the response
  221. func (o *Operation) WithDefaultResponse(response *Response) *Operation {
  222. return o.RespondsWith(0, response)
  223. }
  224. // RespondsWith adds a status code response to the operation.
  225. // When the code is 0 the value of the response will be used as default response value.
  226. // When the value of the response is nil it will be removed from the operation
  227. func (o *Operation) RespondsWith(code int, response *Response) *Operation {
  228. if o.Responses == nil {
  229. o.Responses = new(Responses)
  230. }
  231. if code == 0 {
  232. o.Responses.Default = response
  233. return o
  234. }
  235. if response == nil {
  236. delete(o.Responses.StatusCodeResponses, code)
  237. return o
  238. }
  239. if o.Responses.StatusCodeResponses == nil {
  240. o.Responses.StatusCodeResponses = make(map[int]Response)
  241. }
  242. o.Responses.StatusCodeResponses[code] = *response
  243. return o
  244. }
  245. type opsAlias OperationProps
  246. type gobAlias struct {
  247. Security []map[string]struct {
  248. List []string
  249. Pad bool
  250. }
  251. Alias *opsAlias
  252. SecurityIsEmpty bool
  253. }
  254. // GobEncode provides a safe gob encoder for Operation, including empty security requirements
  255. func (o Operation) GobEncode() ([]byte, error) {
  256. raw := struct {
  257. Ext VendorExtensible
  258. Props OperationProps
  259. }{
  260. Ext: o.VendorExtensible,
  261. Props: o.OperationProps,
  262. }
  263. var b bytes.Buffer
  264. err := gob.NewEncoder(&b).Encode(raw)
  265. return b.Bytes(), err
  266. }
  267. // GobDecode provides a safe gob decoder for Operation, including empty security requirements
  268. func (o *Operation) GobDecode(b []byte) error {
  269. var raw struct {
  270. Ext VendorExtensible
  271. Props OperationProps
  272. }
  273. buf := bytes.NewBuffer(b)
  274. err := gob.NewDecoder(buf).Decode(&raw)
  275. if err != nil {
  276. return err
  277. }
  278. o.VendorExtensible = raw.Ext
  279. o.OperationProps = raw.Props
  280. return nil
  281. }
  282. // GobEncode provides a safe gob encoder for Operation, including empty security requirements
  283. func (op OperationProps) GobEncode() ([]byte, error) {
  284. raw := gobAlias{
  285. Alias: (*opsAlias)(&op),
  286. }
  287. var b bytes.Buffer
  288. if op.Security == nil {
  289. // nil security requirement
  290. err := gob.NewEncoder(&b).Encode(raw)
  291. return b.Bytes(), err
  292. }
  293. if len(op.Security) == 0 {
  294. // empty, but non-nil security requirement
  295. raw.SecurityIsEmpty = true
  296. raw.Alias.Security = nil
  297. err := gob.NewEncoder(&b).Encode(raw)
  298. return b.Bytes(), err
  299. }
  300. raw.Security = make([]map[string]struct {
  301. List []string
  302. Pad bool
  303. }, 0, len(op.Security))
  304. for _, req := range op.Security {
  305. v := make(map[string]struct {
  306. List []string
  307. Pad bool
  308. }, len(req))
  309. for k, val := range req {
  310. v[k] = struct {
  311. List []string
  312. Pad bool
  313. }{
  314. List: val,
  315. }
  316. }
  317. raw.Security = append(raw.Security, v)
  318. }
  319. err := gob.NewEncoder(&b).Encode(raw)
  320. return b.Bytes(), err
  321. }
  322. // GobDecode provides a safe gob decoder for Operation, including empty security requirements
  323. func (op *OperationProps) GobDecode(b []byte) error {
  324. var raw gobAlias
  325. buf := bytes.NewBuffer(b)
  326. err := gob.NewDecoder(buf).Decode(&raw)
  327. if err != nil {
  328. return err
  329. }
  330. if raw.Alias == nil {
  331. return nil
  332. }
  333. switch {
  334. case raw.SecurityIsEmpty:
  335. // empty, but non-nil security requirement
  336. raw.Alias.Security = []map[string][]string{}
  337. case len(raw.Alias.Security) == 0:
  338. // nil security requirement
  339. raw.Alias.Security = nil
  340. default:
  341. raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security))
  342. for _, req := range raw.Security {
  343. v := make(map[string][]string, len(req))
  344. for k, val := range req {
  345. v[k] = make([]string, 0, len(val.List))
  346. v[k] = append(v[k], val.List...)
  347. }
  348. raw.Alias.Security = append(raw.Alias.Security, v)
  349. }
  350. }
  351. *op = *(*OperationProps)(raw.Alias)
  352. return nil
  353. }
上海开阖软件有限公司 沪ICP备12045867号-1