blob: 3b0cd4e285605c2e1b505fd24be0b32fcac7f4ca [file] [log] [blame]
Serge Bazanskicc25bdf2018-10-25 14:02:58 +02001// 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 untyped
16
17import (
18 "fmt"
19 "net/http"
20 "sort"
21 "strings"
22
23 "github.com/go-openapi/analysis"
24 "github.com/go-openapi/errors"
25 "github.com/go-openapi/loads"
26 "github.com/go-openapi/runtime"
27 "github.com/go-openapi/spec"
28 "github.com/go-openapi/strfmt"
29)
30
31// NewAPI creates the default untyped API
32func NewAPI(spec *loads.Document) *API {
33 var an *analysis.Spec
34 if spec != nil && spec.Spec() != nil {
35 an = analysis.New(spec.Spec())
36 }
37 api := &API{
38 spec: spec,
39 analyzer: an,
40 consumers: make(map[string]runtime.Consumer, 10),
41 producers: make(map[string]runtime.Producer, 10),
42 authenticators: make(map[string]runtime.Authenticator),
43 operations: make(map[string]map[string]runtime.OperationHandler),
44 ServeError: errors.ServeError,
45 Models: make(map[string]func() interface{}),
46 formats: strfmt.NewFormats(),
47 }
48 return api.WithJSONDefaults()
49}
50
51// API represents an untyped mux for a swagger spec
52type API struct {
53 spec *loads.Document
54 analyzer *analysis.Spec
55 DefaultProduces string
56 DefaultConsumes string
57 consumers map[string]runtime.Consumer
58 producers map[string]runtime.Producer
59 authenticators map[string]runtime.Authenticator
60 authorizer runtime.Authorizer
61 operations map[string]map[string]runtime.OperationHandler
62 ServeError func(http.ResponseWriter, *http.Request, error)
63 Models map[string]func() interface{}
64 formats strfmt.Registry
65}
66
67// WithJSONDefaults loads the json defaults for this api
68func (d *API) WithJSONDefaults() *API {
69 d.DefaultConsumes = runtime.JSONMime
70 d.DefaultProduces = runtime.JSONMime
71 d.consumers[runtime.JSONMime] = runtime.JSONConsumer()
72 d.producers[runtime.JSONMime] = runtime.JSONProducer()
73 return d
74}
75
76// WithoutJSONDefaults clears the json defaults for this api
77func (d *API) WithoutJSONDefaults() *API {
78 d.DefaultConsumes = ""
79 d.DefaultProduces = ""
80 delete(d.consumers, runtime.JSONMime)
81 delete(d.producers, runtime.JSONMime)
82 return d
83}
84
85// Formats returns the registered string formats
86func (d *API) Formats() strfmt.Registry {
87 if d.formats == nil {
88 d.formats = strfmt.NewFormats()
89 }
90 return d.formats
91}
92
93// RegisterFormat registers a custom format validator
94func (d *API) RegisterFormat(name string, format strfmt.Format, validator strfmt.Validator) {
95 if d.formats == nil {
96 d.formats = strfmt.NewFormats()
97 }
98 d.formats.Add(name, format, validator)
99}
100
101// RegisterAuth registers an auth handler in this api
102func (d *API) RegisterAuth(scheme string, handler runtime.Authenticator) {
103 if d.authenticators == nil {
104 d.authenticators = make(map[string]runtime.Authenticator)
105 }
106 d.authenticators[scheme] = handler
107}
108
109// RegisterAuthorizer registers an authorizer handler in this api
110func (d *API) RegisterAuthorizer(handler runtime.Authorizer) {
111 d.authorizer = handler
112}
113
114// RegisterConsumer registers a consumer for a media type.
115func (d *API) RegisterConsumer(mediaType string, handler runtime.Consumer) {
116 if d.consumers == nil {
117 d.consumers = make(map[string]runtime.Consumer, 10)
118 }
119 d.consumers[strings.ToLower(mediaType)] = handler
120}
121
122// RegisterProducer registers a producer for a media type
123func (d *API) RegisterProducer(mediaType string, handler runtime.Producer) {
124 if d.producers == nil {
125 d.producers = make(map[string]runtime.Producer, 10)
126 }
127 d.producers[strings.ToLower(mediaType)] = handler
128}
129
130// RegisterOperation registers an operation handler for an operation name
131func (d *API) RegisterOperation(method, path string, handler runtime.OperationHandler) {
132 if d.operations == nil {
133 d.operations = make(map[string]map[string]runtime.OperationHandler, 30)
134 }
135 um := strings.ToUpper(method)
136 if b, ok := d.operations[um]; !ok || b == nil {
137 d.operations[um] = make(map[string]runtime.OperationHandler)
138 }
139 d.operations[um][path] = handler
140}
141
142// OperationHandlerFor returns the operation handler for the specified id if it can be found
143func (d *API) OperationHandlerFor(method, path string) (runtime.OperationHandler, bool) {
144 if d.operations == nil {
145 return nil, false
146 }
147 if pi, ok := d.operations[strings.ToUpper(method)]; ok {
148 h, ok := pi[path]
149 return h, ok
150 }
151 return nil, false
152}
153
154// ConsumersFor gets the consumers for the specified media types
155func (d *API) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
156 result := make(map[string]runtime.Consumer)
157 for _, mt := range mediaTypes {
158 if consumer, ok := d.consumers[mt]; ok {
159 result[mt] = consumer
160 }
161 }
162 return result
163}
164
165// ProducersFor gets the producers for the specified media types
166func (d *API) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
167 result := make(map[string]runtime.Producer)
168 for _, mt := range mediaTypes {
169 if producer, ok := d.producers[mt]; ok {
170 result[mt] = producer
171 }
172 }
173 return result
174}
175
176// AuthenticatorsFor gets the authenticators for the specified security schemes
177func (d *API) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
178 result := make(map[string]runtime.Authenticator)
179 for k := range schemes {
180 if a, ok := d.authenticators[k]; ok {
181 result[k] = a
182 }
183 }
184 return result
185}
186
187// AuthorizersFor returns the registered authorizer
188func (d *API) Authorizer() runtime.Authorizer {
189 return d.authorizer
190}
191
192// Validate validates this API for any missing items
193func (d *API) Validate() error {
194 return d.validate()
195}
196
197// validateWith validates the registrations in this API against the provided spec analyzer
198func (d *API) validate() error {
199 var consumes []string
200 for k := range d.consumers {
201 consumes = append(consumes, k)
202 }
203
204 var produces []string
205 for k := range d.producers {
206 produces = append(produces, k)
207 }
208
209 var authenticators []string
210 for k := range d.authenticators {
211 authenticators = append(authenticators, k)
212 }
213
214 var operations []string
215 for m, v := range d.operations {
216 for p := range v {
217 operations = append(operations, fmt.Sprintf("%s %s", strings.ToUpper(m), p))
218 }
219 }
220
221 var definedAuths []string
222 for k := range d.spec.Spec().SecurityDefinitions {
223 definedAuths = append(definedAuths, k)
224 }
225
226 if err := d.verify("consumes", consumes, d.analyzer.RequiredConsumes()); err != nil {
227 return err
228 }
229 if err := d.verify("produces", produces, d.analyzer.RequiredProduces()); err != nil {
230 return err
231 }
232 if err := d.verify("operation", operations, d.analyzer.OperationMethodPaths()); err != nil {
233 return err
234 }
235
236 requiredAuths := d.analyzer.RequiredSecuritySchemes()
237 if err := d.verify("auth scheme", authenticators, requiredAuths); err != nil {
238 return err
239 }
240 if err := d.verify("security definitions", definedAuths, requiredAuths); err != nil {
241 return err
242 }
243 return nil
244}
245
246func (d *API) verify(name string, registrations []string, expectations []string) error {
247
248 sort.Sort(sort.StringSlice(registrations))
249 sort.Sort(sort.StringSlice(expectations))
250
251 expected := map[string]struct{}{}
252 seen := map[string]struct{}{}
253
254 for _, v := range expectations {
255 expected[v] = struct{}{}
256 }
257
258 var unspecified []string
259 for _, v := range registrations {
260 seen[v] = struct{}{}
261 if _, ok := expected[v]; !ok {
262 unspecified = append(unspecified, v)
263 }
264 }
265
266 for k := range seen {
267 delete(expected, k)
268 }
269
270 var unregistered []string
271 for k := range expected {
272 unregistered = append(unregistered, k)
273 }
274 sort.Sort(sort.StringSlice(unspecified))
275 sort.Sort(sort.StringSlice(unregistered))
276
277 if len(unregistered) > 0 || len(unspecified) > 0 {
278 return &errors.APIVerificationFailed{
279 Section: name,
280 MissingSpecification: unspecified,
281 MissingRegistration: unregistered,
282 }
283 }
284
285 return nil
286}