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