...

Source file src/github.com/go-openapi/runtime/middleware/untyped/api.go

Documentation: github.com/go-openapi/runtime/middleware/untyped

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

View as plain text