path.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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. "strings"
  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. // Paths describes the available paths and operations for the API, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathsObject
  24. type Paths struct {
  25. Paths map[string]*Path
  26. spec.VendorExtensible
  27. }
  28. // MarshalJSON is a custom marshal function that knows how to encode Paths as JSON
  29. func (p *Paths) MarshalJSON() ([]byte, error) {
  30. if internal.UseOptimizedJSONMarshalingV3 {
  31. return internal.DeterministicMarshal(p)
  32. }
  33. b1, err := json.Marshal(p.VendorExtensible)
  34. if err != nil {
  35. return nil, err
  36. }
  37. pths := make(map[string]*Path)
  38. for k, v := range p.Paths {
  39. if strings.HasPrefix(k, "/") {
  40. pths[k] = v
  41. }
  42. }
  43. b2, err := json.Marshal(pths)
  44. if err != nil {
  45. return nil, err
  46. }
  47. concated := swag.ConcatJSON(b1, b2)
  48. return concated, nil
  49. }
  50. func (p *Paths) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
  51. m := make(map[string]any, len(p.Extensions)+len(p.Paths))
  52. for k, v := range p.Extensions {
  53. if internal.IsExtensionKey(k) {
  54. m[k] = v
  55. }
  56. }
  57. for k, v := range p.Paths {
  58. if strings.HasPrefix(k, "/") {
  59. m[k] = v
  60. }
  61. }
  62. return opts.MarshalNext(enc, m)
  63. }
  64. // UnmarshalJSON hydrates this items instance with the data from JSON
  65. func (p *Paths) UnmarshalJSON(data []byte) error {
  66. if internal.UseOptimizedJSONUnmarshalingV3 {
  67. return jsonv2.Unmarshal(data, p)
  68. }
  69. var res map[string]json.RawMessage
  70. if err := json.Unmarshal(data, &res); err != nil {
  71. return err
  72. }
  73. for k, v := range res {
  74. if strings.HasPrefix(strings.ToLower(k), "x-") {
  75. if p.Extensions == nil {
  76. p.Extensions = make(map[string]interface{})
  77. }
  78. var d interface{}
  79. if err := json.Unmarshal(v, &d); err != nil {
  80. return err
  81. }
  82. p.Extensions[k] = d
  83. }
  84. if strings.HasPrefix(k, "/") {
  85. if p.Paths == nil {
  86. p.Paths = make(map[string]*Path)
  87. }
  88. var pi *Path
  89. if err := json.Unmarshal(v, &pi); err != nil {
  90. return err
  91. }
  92. p.Paths[k] = pi
  93. }
  94. }
  95. return nil
  96. }
  97. func (p *Paths) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
  98. tok, err := dec.ReadToken()
  99. if err != nil {
  100. return err
  101. }
  102. switch k := tok.Kind(); k {
  103. case 'n':
  104. *p = Paths{}
  105. return nil
  106. case '{':
  107. for {
  108. tok, err := dec.ReadToken()
  109. if err != nil {
  110. return err
  111. }
  112. if tok.Kind() == '}' {
  113. return nil
  114. }
  115. switch k := tok.String(); {
  116. case internal.IsExtensionKey(k):
  117. var ext any
  118. if err := opts.UnmarshalNext(dec, &ext); err != nil {
  119. return err
  120. }
  121. if p.Extensions == nil {
  122. p.Extensions = make(map[string]any)
  123. }
  124. p.Extensions[k] = ext
  125. case len(k) > 0 && k[0] == '/':
  126. pi := Path{}
  127. if err := opts.UnmarshalNext(dec, &pi); err != nil {
  128. return err
  129. }
  130. if p.Paths == nil {
  131. p.Paths = make(map[string]*Path)
  132. }
  133. p.Paths[k] = &pi
  134. default:
  135. _, err := dec.ReadValue() // skip value
  136. if err != nil {
  137. return err
  138. }
  139. }
  140. }
  141. default:
  142. return fmt.Errorf("unknown JSON kind: %v", k)
  143. }
  144. }
  145. // Path describes the operations available on a single path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathItemObject
  146. //
  147. // Note that this struct is actually a thin wrapper around PathProps to make it referable and extensible
  148. type Path struct {
  149. spec.Refable
  150. PathProps
  151. spec.VendorExtensible
  152. }
  153. // MarshalJSON is a custom marshal function that knows how to encode Path as JSON
  154. func (p *Path) MarshalJSON() ([]byte, error) {
  155. if internal.UseOptimizedJSONMarshalingV3 {
  156. return internal.DeterministicMarshal(p)
  157. }
  158. b1, err := json.Marshal(p.Refable)
  159. if err != nil {
  160. return nil, err
  161. }
  162. b2, err := json.Marshal(p.PathProps)
  163. if err != nil {
  164. return nil, err
  165. }
  166. b3, err := json.Marshal(p.VendorExtensible)
  167. if err != nil {
  168. return nil, err
  169. }
  170. return swag.ConcatJSON(b1, b2, b3), nil
  171. }
  172. func (p *Path) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
  173. var x struct {
  174. Ref string `json:"$ref,omitempty"`
  175. spec.Extensions
  176. PathProps
  177. }
  178. x.Ref = p.Refable.Ref.String()
  179. x.Extensions = internal.SanitizeExtensions(p.Extensions)
  180. x.PathProps = p.PathProps
  181. return opts.MarshalNext(enc, x)
  182. }
  183. func (p *Path) UnmarshalJSON(data []byte) error {
  184. if internal.UseOptimizedJSONUnmarshalingV3 {
  185. return jsonv2.Unmarshal(data, p)
  186. }
  187. if err := json.Unmarshal(data, &p.Refable); err != nil {
  188. return err
  189. }
  190. if err := json.Unmarshal(data, &p.PathProps); err != nil {
  191. return err
  192. }
  193. if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
  194. return err
  195. }
  196. return nil
  197. }
  198. func (p *Path) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
  199. var x struct {
  200. spec.Extensions
  201. PathProps
  202. }
  203. if err := opts.UnmarshalNext(dec, &x); err != nil {
  204. return err
  205. }
  206. if err := internal.JSONRefFromMap(&p.Ref.Ref, x.Extensions); err != nil {
  207. return err
  208. }
  209. p.Extensions = internal.SanitizeExtensions(x.Extensions)
  210. p.PathProps = x.PathProps
  211. return nil
  212. }
  213. // PathProps describes the operations available on a single path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathItemObject
  214. type PathProps struct {
  215. // Summary holds a summary for all operations in this path
  216. Summary string `json:"summary,omitempty"`
  217. // Description holds a description for all operations in this path
  218. Description string `json:"description,omitempty"`
  219. // Get defines GET operation
  220. Get *Operation `json:"get,omitempty"`
  221. // Put defines PUT operation
  222. Put *Operation `json:"put,omitempty"`
  223. // Post defines POST operation
  224. Post *Operation `json:"post,omitempty"`
  225. // Delete defines DELETE operation
  226. Delete *Operation `json:"delete,omitempty"`
  227. // Options defines OPTIONS operation
  228. Options *Operation `json:"options,omitempty"`
  229. // Head defines HEAD operation
  230. Head *Operation `json:"head,omitempty"`
  231. // Patch defines PATCH operation
  232. Patch *Operation `json:"patch,omitempty"`
  233. // Trace defines TRACE operation
  234. Trace *Operation `json:"trace,omitempty"`
  235. // Servers is an alternative server array to service all operations in this path
  236. Servers []*Server `json:"servers,omitempty"`
  237. // Parameters a list of parameters that are applicable for this operation
  238. Parameters []*Parameter `json:"parameters,omitempty"`
  239. }