Matthias Andreas Benkard | 832a54e | 2019-01-29 09:27:38 +0100 | [diff] [blame] | 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 | |
| 15 | package spec |
| 16 | |
| 17 | import ( |
| 18 | "encoding/json" |
| 19 | |
| 20 | "github.com/go-openapi/jsonpointer" |
| 21 | "github.com/go-openapi/swag" |
| 22 | ) |
| 23 | |
| 24 | type OperationProps struct { |
| 25 | Description string `json:"description,omitempty"` |
| 26 | Consumes []string `json:"consumes,omitempty"` |
| 27 | Produces []string `json:"produces,omitempty"` |
| 28 | Schemes []string `json:"schemes,omitempty"` // the scheme, when present must be from [http, https, ws, wss] |
| 29 | Tags []string `json:"tags,omitempty"` |
| 30 | Summary string `json:"summary,omitempty"` |
| 31 | ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` |
| 32 | ID string `json:"operationId,omitempty"` |
| 33 | Deprecated bool `json:"deprecated,omitempty"` |
| 34 | Security []map[string][]string `json:"security,omitempty"` //Special case, see MarshalJSON function |
| 35 | Parameters []Parameter `json:"parameters,omitempty"` |
| 36 | Responses *Responses `json:"responses,omitempty"` |
| 37 | } |
| 38 | |
| 39 | // MarshalJSON takes care of serializing operation properties to JSON |
| 40 | // |
| 41 | // We use a custom marhaller here to handle a special cases related |
| 42 | // the Security field. We need to preserve zero length slice |
| 43 | // while omiting the field when the value is nil/unset. |
| 44 | func (op OperationProps) MarshalJSON() ([]byte, error) { |
| 45 | type Alias OperationProps |
| 46 | if op.Security == nil { |
| 47 | return json.Marshal(&struct { |
| 48 | Security []map[string][]string `json:"security,omitempty"` |
| 49 | *Alias |
| 50 | }{ |
| 51 | Security: op.Security, |
| 52 | Alias: (*Alias)(&op), |
| 53 | }) |
| 54 | } |
| 55 | return json.Marshal(&struct { |
| 56 | Security []map[string][]string `json:"security"` |
| 57 | *Alias |
| 58 | }{ |
| 59 | Security: op.Security, |
| 60 | Alias: (*Alias)(&op), |
| 61 | }) |
| 62 | } |
| 63 | |
| 64 | // Operation describes a single API operation on a path. |
| 65 | // |
| 66 | // For more information: http://goo.gl/8us55a#operationObject |
| 67 | type Operation struct { |
| 68 | VendorExtensible |
| 69 | OperationProps |
| 70 | } |
| 71 | |
| 72 | // SuccessResponse gets a success response model |
| 73 | func (o *Operation) SuccessResponse() (*Response, int, bool) { |
| 74 | if o.Responses == nil { |
| 75 | return nil, 0, false |
| 76 | } |
| 77 | |
| 78 | for k, v := range o.Responses.StatusCodeResponses { |
| 79 | if k/100 == 2 { |
| 80 | return &v, k, true |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | return o.Responses.Default, 0, false |
| 85 | } |
| 86 | |
| 87 | // JSONLookup look up a value by the json property name |
| 88 | func (o Operation) JSONLookup(token string) (interface{}, error) { |
| 89 | if ex, ok := o.Extensions[token]; ok { |
| 90 | return &ex, nil |
| 91 | } |
| 92 | r, _, err := jsonpointer.GetForToken(o.OperationProps, token) |
| 93 | return r, err |
| 94 | } |
| 95 | |
| 96 | // UnmarshalJSON hydrates this items instance with the data from JSON |
| 97 | func (o *Operation) UnmarshalJSON(data []byte) error { |
| 98 | if err := json.Unmarshal(data, &o.OperationProps); err != nil { |
| 99 | return err |
| 100 | } |
| 101 | if err := json.Unmarshal(data, &o.VendorExtensible); err != nil { |
| 102 | return err |
| 103 | } |
| 104 | return nil |
| 105 | } |
| 106 | |
| 107 | // MarshalJSON converts this items object to JSON |
| 108 | func (o Operation) MarshalJSON() ([]byte, error) { |
| 109 | b1, err := json.Marshal(o.OperationProps) |
| 110 | if err != nil { |
| 111 | return nil, err |
| 112 | } |
| 113 | b2, err := json.Marshal(o.VendorExtensible) |
| 114 | if err != nil { |
| 115 | return nil, err |
| 116 | } |
| 117 | concated := swag.ConcatJSON(b1, b2) |
| 118 | return concated, nil |
| 119 | } |
| 120 | |
| 121 | // NewOperation creates a new operation instance. |
| 122 | // It expects an ID as parameter but not passing an ID is also valid. |
| 123 | func NewOperation(id string) *Operation { |
| 124 | op := new(Operation) |
| 125 | op.ID = id |
| 126 | return op |
| 127 | } |
| 128 | |
| 129 | // WithID sets the ID property on this operation, allows for chaining. |
| 130 | func (o *Operation) WithID(id string) *Operation { |
| 131 | o.ID = id |
| 132 | return o |
| 133 | } |
| 134 | |
| 135 | // WithDescription sets the description on this operation, allows for chaining |
| 136 | func (o *Operation) WithDescription(description string) *Operation { |
| 137 | o.Description = description |
| 138 | return o |
| 139 | } |
| 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 | |
| 147 | // WithExternalDocs sets/removes the external docs for/from this operation. |
| 148 | // When you pass empty strings as params the external documents will be removed. |
| 149 | // When you pass non-empty string as one value then those values will be used on the external docs object. |
| 150 | // So when you pass a non-empty description, you should also pass the url and vice versa. |
| 151 | func (o *Operation) WithExternalDocs(description, url string) *Operation { |
| 152 | if description == "" && url == "" { |
| 153 | o.ExternalDocs = nil |
| 154 | return o |
| 155 | } |
| 156 | |
| 157 | if o.ExternalDocs == nil { |
| 158 | o.ExternalDocs = &ExternalDocumentation{} |
| 159 | } |
| 160 | o.ExternalDocs.Description = description |
| 161 | o.ExternalDocs.URL = url |
| 162 | return o |
| 163 | } |
| 164 | |
| 165 | // Deprecate marks the operation as deprecated |
| 166 | func (o *Operation) Deprecate() *Operation { |
| 167 | o.Deprecated = true |
| 168 | return o |
| 169 | } |
| 170 | |
| 171 | // Undeprecate marks the operation as not deprected |
| 172 | func (o *Operation) Undeprecate() *Operation { |
| 173 | o.Deprecated = false |
| 174 | return o |
| 175 | } |
| 176 | |
| 177 | // WithConsumes adds media types for incoming body values |
| 178 | func (o *Operation) WithConsumes(mediaTypes ...string) *Operation { |
| 179 | o.Consumes = append(o.Consumes, mediaTypes...) |
| 180 | return o |
| 181 | } |
| 182 | |
| 183 | // WithProduces adds media types for outgoing body values |
| 184 | func (o *Operation) WithProduces(mediaTypes ...string) *Operation { |
| 185 | o.Produces = append(o.Produces, mediaTypes...) |
| 186 | return o |
| 187 | } |
| 188 | |
| 189 | // WithTags adds tags for this operation |
| 190 | func (o *Operation) WithTags(tags ...string) *Operation { |
| 191 | o.Tags = append(o.Tags, tags...) |
| 192 | return o |
| 193 | } |
| 194 | |
| 195 | // AddParam adds a parameter to this operation, when a parameter for that location |
| 196 | // and with that name already exists it will be replaced |
| 197 | func (o *Operation) AddParam(param *Parameter) *Operation { |
| 198 | if param == nil { |
| 199 | return o |
| 200 | } |
| 201 | |
| 202 | for i, p := range o.Parameters { |
| 203 | if p.Name == param.Name && p.In == param.In { |
| 204 | params := append(o.Parameters[:i], *param) |
| 205 | params = append(params, o.Parameters[i+1:]...) |
| 206 | o.Parameters = params |
| 207 | return o |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | o.Parameters = append(o.Parameters, *param) |
| 212 | return o |
| 213 | } |
| 214 | |
| 215 | // RemoveParam removes a parameter from the operation |
| 216 | func (o *Operation) RemoveParam(name, in string) *Operation { |
| 217 | for i, p := range o.Parameters { |
| 218 | if p.Name == name && p.In == name { |
| 219 | o.Parameters = append(o.Parameters[:i], o.Parameters[i+1:]...) |
| 220 | return o |
| 221 | } |
| 222 | } |
| 223 | return o |
| 224 | } |
| 225 | |
| 226 | // SecuredWith adds a security scope to this operation. |
| 227 | func (o *Operation) SecuredWith(name string, scopes ...string) *Operation { |
| 228 | o.Security = append(o.Security, map[string][]string{name: scopes}) |
| 229 | return o |
| 230 | } |
| 231 | |
| 232 | // WithDefaultResponse adds a default response to the operation. |
| 233 | // Passing a nil value will remove the response |
| 234 | func (o *Operation) WithDefaultResponse(response *Response) *Operation { |
| 235 | return o.RespondsWith(0, response) |
| 236 | } |
| 237 | |
| 238 | // RespondsWith adds a status code response to the operation. |
| 239 | // When the code is 0 the value of the response will be used as default response value. |
| 240 | // When the value of the response is nil it will be removed from the operation |
| 241 | func (o *Operation) RespondsWith(code int, response *Response) *Operation { |
| 242 | if o.Responses == nil { |
| 243 | o.Responses = new(Responses) |
| 244 | } |
| 245 | if code == 0 { |
| 246 | o.Responses.Default = response |
| 247 | return o |
| 248 | } |
| 249 | if response == nil { |
| 250 | delete(o.Responses.StatusCodeResponses, code) |
| 251 | return o |
| 252 | } |
| 253 | if o.Responses.StatusCodeResponses == nil { |
| 254 | o.Responses.StatusCodeResponses = make(map[int]Response) |
| 255 | } |
| 256 | o.Responses.StatusCodeResponses[code] = *response |
| 257 | return o |
| 258 | } |