// Spec validates a spec document // It validates the spec json against the json schema for swagger // and then validates a number of extra rules that can't be expressed in json schema: // // - definition can't declare a property that's already defined by one of its ancestors // - definition's ancestor can't be a descendant of the same model // - each api path should be non-verbatim (account for path param names) unique per method // - each security reference should contain only unique scopes // - each security scope in a security definition should be unique // - each path parameter should correspond to a parameter placeholder and vice versa // - each referencable defintion must have references // - each definition property listed in the required array must be defined in the properties of the model // - each parameter should have a unique `name` and `type` combination // - each operation should have only 1 parameter of type body // - each reference must point to a valid object // - every default value that is specified must validate against the schema for that property // - items property is required for all schemas/definitions of type `array` func Spec(doc *spec.Document, formats strfmt.Registry) error { errs, _ /*warns*/ := validate.NewSpecValidator(doc.Schema(), formats).Validate(doc) if errs.HasErrors() { return errors.CompositeValidationError(errs.Errors...) } return nil }
func petAPIRouterBuilder(spec *spec.Document, api *untyped.API) *defaultRouteBuilder { builder := newDefaultRouteBuilder(spec, newRoutableUntypedAPI(spec, api, new(Context))) builder.AddRoute("GET", "/pets", spec.AllPaths()["/pets"].Get) builder.AddRoute("POST", "/pets", spec.AllPaths()["/pets"].Post) builder.AddRoute("DELETE", "/pets/{id}", spec.AllPaths()["/pets/{id}"].Delete) builder.AddRoute("GET", "/pets/{id}", spec.AllPaths()["/pets/{id}"].Get) return builder }
func gatherModels(specDoc *spec.Document, modelNames []string) map[string]spec.Schema { models, mnc := make(map[string]spec.Schema), len(modelNames) for k, v := range specDoc.Spec().Definitions { for _, nm := range modelNames { if mnc == 0 || k == nm { models[k] = v } } } return models }
func newRoutableUntypedAPI(spec *spec.Document, api *untyped.API, context *Context) *routableUntypedAPI { var handlers map[string]http.Handler if spec == nil || api == nil { return nil } for _, hls := range spec.Operations() { for _, op := range hls { schemes := spec.SecurityDefinitionsFor(op) if oh, ok := api.OperationHandlerFor(op.ID); ok { if handlers == nil { handlers = make(map[string]http.Handler) } handlers[op.ID] = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // lookup route info in the context route, _ := context.RouteInfo(r) // bind and validate the request using reflection bound, validation := context.BindAndValidate(r, route) if validation != nil { context.Respond(w, r, route.Produces, route, validation) return } // actually handle the request result, err := oh.Handle(bound) if err != nil { // respond with failure context.Respond(w, r, route.Produces, route, err) return } // respond with success context.Respond(w, r, route.Produces, route, result) }) if len(schemes) > 0 { handlers[op.ID] = newSecureAPI(context, handlers[op.ID]) } } } } return &routableUntypedAPI{ api: api, handlers: handlers, defaultProduces: api.DefaultProduces, defaultConsumes: api.DefaultConsumes, } }
// DefaultRouter creates a default implemenation of the router func DefaultRouter(spec *spec.Document, api RoutableAPI) Router { builder := newDefaultRouteBuilder(spec, api) if spec != nil { for method, paths := range spec.Operations() { for path, operation := range paths { builder.AddRoute(method, path, operation) } } } return builder.Build() }
// Validate validates the swagger spec func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Result) { var sd *spec.Document switch v := data.(type) { case *spec.Document: sd = v } if sd == nil { errs = sErr(errors.New(500, "spec validator can only validate spec.Document objects")) return } s.spec = sd errs = new(Result) warnings = new(Result) schv := NewSchemaValidator(s.schema, nil, "", s.KnownFormats) errs.Merge(schv.Validate(sd.Spec())) // error - if errs.HasErrors() { return // no point in continuing } errs.Merge(s.validateReferencesValid()) // error - if errs.HasErrors() { return // no point in continuing } errs.Merge(s.validateDuplicatePropertyNames()) // error - errs.Merge(s.validateParameters()) // error - errs.Merge(s.validateItems()) // error - errs.Merge(s.validateRequiredDefinitions()) // error - errs.Merge(s.validateDefaultValueValidAgainstSchema()) // error - errs.Merge(s.validateExamplesValidAgainstSchema()) // error - warnings.Merge(s.validateUniqueSecurityScopes()) // warning warnings.Merge(s.validateUniqueScopesSecurityDefinitions()) // warning warnings.Merge(s.validateReferenced()) // warning return }
// New creates a new default runtime for a swagger api client. func New(swaggerSpec *spec.Document, host string) *Runtime { var rt Runtime rt.DefaultMediaType = httpkit.JSONMime rt.Consumers = map[string]httpkit.Consumer{ httpkit.JSONMime: httpkit.JSONConsumer(), } rt.Producers = map[string]httpkit.Producer{ httpkit.JSONMime: httpkit.JSONProducer(), } rt.Spec = swaggerSpec rt.Transport = http.DefaultTransport rt.client = http.DefaultClient rt.Host = host rt.BasePath = swaggerSpec.BasePath() rt.methodsAndPaths = make(map[string]methodAndPath) for mth, pathItem := range rt.Spec.Operations() { for pth, op := range pathItem { rt.methodsAndPaths[op.ID] = methodAndPath{mth, pth} } } return &rt }
func appNameOrDefault(specDoc *spec.Document, name, defaultName string) string { if name == "" { if specDoc.Spec().Info != nil && specDoc.Spec().Info.Title != "" { name = specDoc.Spec().Info.Title } else { name = defaultName } } return swag.ToGoName(name) }
func gatherOperations(specDoc *spec.Document, operationIDs []string) map[string]spec.Operation { operations := make(map[string]spec.Operation) if len(operationIDs) == 0 { for _, k := range specDoc.OperationIDs() { if op, ok := specDoc.OperationForName(k); ok { operations[k] = *op } } } else { for _, k := range specDoc.OperationIDs() { for _, nm := range operationIDs { if k == nm { if op, ok := specDoc.OperationForName(k); ok { operations[k] = *op } } } } } return operations }