response.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. Copyright 2021 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package spec3
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "strconv"
  18. "github.com/go-openapi/swag"
  19. "k8s.io/kube-openapi/pkg/internal"
  20. jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
  21. "k8s.io/kube-openapi/pkg/validation/spec"
  22. )
  23. // Responses holds the list of possible responses as they are returned from executing this operation
  24. //
  25. // Note that this struct is actually a thin wrapper around ResponsesProps to make it referable and extensible
  26. type Responses struct {
  27. ResponsesProps
  28. spec.VendorExtensible
  29. }
  30. // MarshalJSON is a custom marshal function that knows how to encode Responses as JSON
  31. func (r *Responses) MarshalJSON() ([]byte, error) {
  32. if internal.UseOptimizedJSONMarshalingV3 {
  33. return internal.DeterministicMarshal(r)
  34. }
  35. b1, err := json.Marshal(r.ResponsesProps)
  36. if err != nil {
  37. return nil, err
  38. }
  39. b2, err := json.Marshal(r.VendorExtensible)
  40. if err != nil {
  41. return nil, err
  42. }
  43. return swag.ConcatJSON(b1, b2), nil
  44. }
  45. func (r Responses) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
  46. type ArbitraryKeys map[string]interface{}
  47. var x struct {
  48. ArbitraryKeys
  49. Default *Response `json:"default,omitzero"`
  50. }
  51. x.ArbitraryKeys = make(map[string]any, len(r.Extensions)+len(r.StatusCodeResponses))
  52. for k, v := range r.Extensions {
  53. if internal.IsExtensionKey(k) {
  54. x.ArbitraryKeys[k] = v
  55. }
  56. }
  57. for k, v := range r.StatusCodeResponses {
  58. x.ArbitraryKeys[strconv.Itoa(k)] = v
  59. }
  60. x.Default = r.Default
  61. return opts.MarshalNext(enc, x)
  62. }
  63. func (r *Responses) UnmarshalJSON(data []byte) error {
  64. if internal.UseOptimizedJSONUnmarshalingV3 {
  65. return jsonv2.Unmarshal(data, r)
  66. }
  67. if err := json.Unmarshal(data, &r.ResponsesProps); err != nil {
  68. return err
  69. }
  70. if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
  71. return err
  72. }
  73. return nil
  74. }
  75. // ResponsesProps holds the list of possible responses as they are returned from executing this operation
  76. type ResponsesProps struct {
  77. // Default holds the documentation of responses other than the ones declared for specific HTTP response codes. Use this field to cover undeclared responses
  78. Default *Response `json:"-"`
  79. // StatusCodeResponses holds a map of any HTTP status code to the response definition
  80. StatusCodeResponses map[int]*Response `json:"-"`
  81. }
  82. // MarshalJSON is a custom marshal function that knows how to encode ResponsesProps as JSON
  83. func (r ResponsesProps) MarshalJSON() ([]byte, error) {
  84. toser := map[string]*Response{}
  85. if r.Default != nil {
  86. toser["default"] = r.Default
  87. }
  88. for k, v := range r.StatusCodeResponses {
  89. toser[strconv.Itoa(k)] = v
  90. }
  91. return json.Marshal(toser)
  92. }
  93. // UnmarshalJSON unmarshals responses from JSON
  94. func (r *ResponsesProps) UnmarshalJSON(data []byte) error {
  95. if internal.UseOptimizedJSONUnmarshalingV3 {
  96. return jsonv2.Unmarshal(data, r)
  97. }
  98. var res map[string]json.RawMessage
  99. if err := json.Unmarshal(data, &res); err != nil {
  100. return err
  101. }
  102. if v, ok := res["default"]; ok {
  103. value := Response{}
  104. if err := json.Unmarshal(v, &value); err != nil {
  105. return err
  106. }
  107. r.Default = &value
  108. delete(res, "default")
  109. }
  110. for k, v := range res {
  111. // Take all integral keys
  112. if nk, err := strconv.Atoi(k); err == nil {
  113. if r.StatusCodeResponses == nil {
  114. r.StatusCodeResponses = map[int]*Response{}
  115. }
  116. value := Response{}
  117. if err := json.Unmarshal(v, &value); err != nil {
  118. return err
  119. }
  120. r.StatusCodeResponses[nk] = &value
  121. }
  122. }
  123. return nil
  124. }
  125. func (r *Responses) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) (err error) {
  126. tok, err := dec.ReadToken()
  127. if err != nil {
  128. return err
  129. }
  130. switch k := tok.Kind(); k {
  131. case 'n':
  132. *r = Responses{}
  133. return nil
  134. case '{':
  135. for {
  136. tok, err := dec.ReadToken()
  137. if err != nil {
  138. return err
  139. }
  140. if tok.Kind() == '}' {
  141. return nil
  142. }
  143. switch k := tok.String(); {
  144. case internal.IsExtensionKey(k):
  145. var ext any
  146. if err := opts.UnmarshalNext(dec, &ext); err != nil {
  147. return err
  148. }
  149. if r.Extensions == nil {
  150. r.Extensions = make(map[string]any)
  151. }
  152. r.Extensions[k] = ext
  153. case k == "default":
  154. resp := Response{}
  155. if err := opts.UnmarshalNext(dec, &resp); err != nil {
  156. return err
  157. }
  158. r.ResponsesProps.Default = &resp
  159. default:
  160. if nk, err := strconv.Atoi(k); err == nil {
  161. resp := Response{}
  162. if err := opts.UnmarshalNext(dec, &resp); err != nil {
  163. return err
  164. }
  165. if r.StatusCodeResponses == nil {
  166. r.StatusCodeResponses = map[int]*Response{}
  167. }
  168. r.StatusCodeResponses[nk] = &resp
  169. }
  170. }
  171. }
  172. default:
  173. return fmt.Errorf("unknown JSON kind: %v", k)
  174. }
  175. }
  176. // Response describes a single response from an API Operation, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject
  177. //
  178. // Note that this struct is actually a thin wrapper around ResponseProps to make it referable and extensible
  179. type Response struct {
  180. spec.Refable
  181. ResponseProps
  182. spec.VendorExtensible
  183. }
  184. // MarshalJSON is a custom marshal function that knows how to encode Response as JSON
  185. func (r *Response) MarshalJSON() ([]byte, error) {
  186. if internal.UseOptimizedJSONMarshalingV3 {
  187. return internal.DeterministicMarshal(r)
  188. }
  189. b1, err := json.Marshal(r.Refable)
  190. if err != nil {
  191. return nil, err
  192. }
  193. b2, err := json.Marshal(r.ResponseProps)
  194. if err != nil {
  195. return nil, err
  196. }
  197. b3, err := json.Marshal(r.VendorExtensible)
  198. if err != nil {
  199. return nil, err
  200. }
  201. return swag.ConcatJSON(b1, b2, b3), nil
  202. }
  203. func (r Response) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
  204. var x struct {
  205. Ref string `json:"$ref,omitempty"`
  206. spec.Extensions
  207. ResponseProps `json:",inline"`
  208. }
  209. x.Ref = r.Refable.Ref.String()
  210. x.Extensions = internal.SanitizeExtensions(r.Extensions)
  211. x.ResponseProps = r.ResponseProps
  212. return opts.MarshalNext(enc, x)
  213. }
  214. func (r *Response) UnmarshalJSON(data []byte) error {
  215. if internal.UseOptimizedJSONUnmarshalingV3 {
  216. return jsonv2.Unmarshal(data, r)
  217. }
  218. if err := json.Unmarshal(data, &r.Refable); err != nil {
  219. return err
  220. }
  221. if err := json.Unmarshal(data, &r.ResponseProps); err != nil {
  222. return err
  223. }
  224. if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
  225. return err
  226. }
  227. return nil
  228. }
  229. func (r *Response) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
  230. var x struct {
  231. spec.Extensions
  232. ResponseProps
  233. }
  234. if err := opts.UnmarshalNext(dec, &x); err != nil {
  235. return err
  236. }
  237. if err := internal.JSONRefFromMap(&r.Ref.Ref, x.Extensions); err != nil {
  238. return err
  239. }
  240. r.Extensions = internal.SanitizeExtensions(x.Extensions)
  241. r.ResponseProps = x.ResponseProps
  242. return nil
  243. }
  244. // ResponseProps describes a single response from an API Operation, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject
  245. type ResponseProps struct {
  246. // Description holds a short description of the response
  247. Description string `json:"description,omitempty"`
  248. // Headers holds a maps of a headers name to its definition
  249. Headers map[string]*Header `json:"headers,omitempty"`
  250. // Content holds a map containing descriptions of potential response payloads
  251. Content map[string]*MediaType `json:"content,omitempty"`
  252. // Links is a map of operations links that can be followed from the response
  253. Links map[string]*Link `json:"links,omitempty"`
  254. }
  255. // Link represents a possible design-time link for a response, more at https://swagger.io/specification/#link-object
  256. type Link struct {
  257. spec.Refable
  258. LinkProps
  259. spec.VendorExtensible
  260. }
  261. // MarshalJSON is a custom marshal function that knows how to encode Link as JSON
  262. func (r *Link) MarshalJSON() ([]byte, error) {
  263. if internal.UseOptimizedJSONMarshalingV3 {
  264. return internal.DeterministicMarshal(r)
  265. }
  266. b1, err := json.Marshal(r.Refable)
  267. if err != nil {
  268. return nil, err
  269. }
  270. b2, err := json.Marshal(r.LinkProps)
  271. if err != nil {
  272. return nil, err
  273. }
  274. b3, err := json.Marshal(r.VendorExtensible)
  275. if err != nil {
  276. return nil, err
  277. }
  278. return swag.ConcatJSON(b1, b2, b3), nil
  279. }
  280. func (r *Link) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
  281. var x struct {
  282. Ref string `json:"$ref,omitempty"`
  283. spec.Extensions
  284. LinkProps `json:",inline"`
  285. }
  286. x.Ref = r.Refable.Ref.String()
  287. x.Extensions = internal.SanitizeExtensions(r.Extensions)
  288. x.LinkProps = r.LinkProps
  289. return opts.MarshalNext(enc, x)
  290. }
  291. func (r *Link) UnmarshalJSON(data []byte) error {
  292. if internal.UseOptimizedJSONUnmarshalingV3 {
  293. return jsonv2.Unmarshal(data, r)
  294. }
  295. if err := json.Unmarshal(data, &r.Refable); err != nil {
  296. return err
  297. }
  298. if err := json.Unmarshal(data, &r.LinkProps); err != nil {
  299. return err
  300. }
  301. if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
  302. return err
  303. }
  304. return nil
  305. }
  306. func (l *Link) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
  307. var x struct {
  308. spec.Extensions
  309. LinkProps
  310. }
  311. if err := opts.UnmarshalNext(dec, &x); err != nil {
  312. return err
  313. }
  314. if err := internal.JSONRefFromMap(&l.Ref.Ref, x.Extensions); err != nil {
  315. return err
  316. }
  317. l.Extensions = internal.SanitizeExtensions(x.Extensions)
  318. l.LinkProps = x.LinkProps
  319. return nil
  320. }
  321. // LinkProps describes a single response from an API Operation, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject
  322. type LinkProps struct {
  323. // OperationId is the name of an existing, resolvable OAS operation
  324. OperationId string `json:"operationId,omitempty"`
  325. // Parameters is a map representing parameters to pass to an operation as specified with operationId or identified via operationRef
  326. Parameters map[string]interface{} `json:"parameters,omitempty"`
  327. // Description holds a description of the link
  328. Description string `json:"description,omitempty"`
  329. // RequestBody is a literal value or expresion to use as a request body when calling the target operation
  330. RequestBody interface{} `json:"requestBody,omitempty"`
  331. // Server holds a server object used by the target operation
  332. Server *Server `json:"server,omitempty"`
  333. }