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
15package spec
16
17import (
18	"encoding/json"
19	"fmt"
20	"reflect"
21	"strconv"
22
23	"github.com/go-openapi/swag"
24)
25
26// Responses is a container for the expected responses of an operation.
27// The container maps a HTTP response code to the expected response.
28// It is not expected from the documentation to necessarily cover all possible HTTP response codes,
29// since they may not be known in advance. However, it is expected from the documentation to cover
30// a successful operation response and any known errors.
31//
32// The `default` can be used a default response object for all HTTP codes that are not covered
33// individually by the specification.
34//
35// The `Responses Object` MUST contain at least one response code, and it SHOULD be the response
36// for a successful operation call.
37//
38// For more information: http://goo.gl/8us55a#responsesObject
39type Responses struct {
40	VendorExtensible
41	ResponsesProps
42}
43
44// JSONLookup implements an interface to customize json pointer lookup
45func (r Responses) JSONLookup(token string) (interface{}, error) {
46	if token == "default" {
47		return r.Default, nil
48	}
49	if ex, ok := r.Extensions[token]; ok {
50		return &ex, nil
51	}
52	if i, err := strconv.Atoi(token); err == nil {
53		if scr, ok := r.StatusCodeResponses[i]; ok {
54			return scr, nil
55		}
56	}
57	return nil, fmt.Errorf("object has no field %q", token)
58}
59
60// UnmarshalJSON hydrates this items instance with the data from JSON
61func (r *Responses) UnmarshalJSON(data []byte) error {
62	if err := json.Unmarshal(data, &r.ResponsesProps); err != nil {
63		return err
64	}
65	if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
66		return err
67	}
68	if reflect.DeepEqual(ResponsesProps{}, r.ResponsesProps) {
69		r.ResponsesProps = ResponsesProps{}
70	}
71	return nil
72}
73
74// MarshalJSON converts this items object to JSON
75func (r Responses) MarshalJSON() ([]byte, error) {
76	b1, err := json.Marshal(r.ResponsesProps)
77	if err != nil {
78		return nil, err
79	}
80	b2, err := json.Marshal(r.VendorExtensible)
81	if err != nil {
82		return nil, err
83	}
84	concated := swag.ConcatJSON(b1, b2)
85	return concated, nil
86}
87
88// ResponsesProps describes all responses for an operation.
89// It tells what is the default response and maps all responses with a
90// HTTP status code.
91type ResponsesProps struct {
92	Default             *Response
93	StatusCodeResponses map[int]Response
94}
95
96// MarshalJSON marshals responses as JSON
97func (r ResponsesProps) MarshalJSON() ([]byte, error) {
98	toser := map[string]Response{}
99	if r.Default != nil {
100		toser["default"] = *r.Default
101	}
102	for k, v := range r.StatusCodeResponses {
103		toser[strconv.Itoa(k)] = v
104	}
105	return json.Marshal(toser)
106}
107
108// UnmarshalJSON unmarshals responses from JSON
109func (r *ResponsesProps) UnmarshalJSON(data []byte) error {
110	var res map[string]Response
111	if err := json.Unmarshal(data, &res); err != nil {
112		return nil
113	}
114	if v, ok := res["default"]; ok {
115		r.Default = &v
116		delete(res, "default")
117	}
118	for k, v := range res {
119		if nk, err := strconv.Atoi(k); err == nil {
120			if r.StatusCodeResponses == nil {
121				r.StatusCodeResponses = map[int]Response{}
122			}
123			r.StatusCodeResponses[nk] = v
124		}
125	}
126	return nil
127}
128