summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-openapi/validate/spec.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-openapi/validate/spec.go')
-rw-r--r--vendor/github.com/go-openapi/validate/spec.go210
1 files changed, 114 insertions, 96 deletions
diff --git a/vendor/github.com/go-openapi/validate/spec.go b/vendor/github.com/go-openapi/validate/spec.go
index 08ccd22fef..f30dd79e38 100644
--- a/vendor/github.com/go-openapi/validate/spec.go
+++ b/vendor/github.com/go-openapi/validate/spec.go
@@ -71,25 +71,22 @@ func NewSpecValidator(schema *spec.Schema, formats strfmt.Registry) *SpecValidat
}
// Validate validates the swagger spec
-func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Result) {
+func (s *SpecValidator) Validate(data interface{}) (*Result, *Result) {
var sd *loads.Document
- errs = new(Result)
+ errs, warnings := new(Result), new(Result)
- switch v := data.(type) {
- case *loads.Document:
+ if v, ok := data.(*loads.Document); ok {
sd = v
}
if sd == nil {
errs.AddErrors(invalidDocumentMsg())
- return
+ return errs, warnings // no point in continuing
}
s.spec = sd
s.analyzer = analysis.New(sd.Spec())
- warnings = new(Result)
-
// Swagger schema validator
- schv := NewSchemaValidator(s.schema, nil, "", s.KnownFormats)
+ schv := NewSchemaValidator(s.schema, nil, "", s.KnownFormats, SwaggerSchema(true))
var obj interface{}
// Raw spec unmarshalling errors
@@ -109,13 +106,13 @@ func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Resu
errs.Merge(schv.Validate(obj)) // error -
// There may be a point in continuing to try and determine more accurate errors
if !s.Options.ContinueOnErrors && errs.HasErrors() {
- return // no point in continuing
+ return errs, warnings // no point in continuing
}
errs.Merge(s.validateReferencesValid()) // error -
// There may be a point in continuing to try and determine more accurate errors
if !s.Options.ContinueOnErrors && errs.HasErrors() {
- return // no point in continuing
+ return errs, warnings // no point in continuing
}
errs.Merge(s.validateDuplicateOperationIDs())
@@ -129,7 +126,7 @@ func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Resu
// There may be a point in continuing to try and determine more accurate errors
if !s.Options.ContinueOnErrors && errs.HasErrors() {
- return // no point in continuing
+ return errs, warnings // no point in continuing
}
// Values provided as default MUST validate their schema
@@ -147,7 +144,7 @@ func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Resu
//errs.Merge(s.validateRefNoSibling()) // warning only
errs.Merge(s.validateReferenced()) // warning only
- return
+ return errs, warnings
}
func (s *SpecValidator) validateNonEmptyPathParamNames() *Result {
@@ -172,9 +169,17 @@ func (s *SpecValidator) validateNonEmptyPathParamNames() *Result {
func (s *SpecValidator) validateDuplicateOperationIDs() *Result {
// OperationID, if specified, must be unique across the board
+ var analyzer *analysis.Spec
+ if s.expanded != nil {
+ // $ref are valid: we can analyze operations on an expanded spec
+ analyzer = analysis.New(s.expanded.Spec())
+ } else {
+ // fallback on possible incomplete picture because of previous errors
+ analyzer = s.analyzer
+ }
res := new(Result)
known := make(map[string]int)
- for _, v := range s.analyzer.OperationIDs() {
+ for _, v := range analyzer.OperationIDs() {
if v != "" {
known[v]++
}
@@ -336,14 +341,14 @@ func (s *SpecValidator) validateItems() *Result {
for path, op := range pi {
for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
- if param.TypeName() == "array" && param.ItemsTypeName() == "" {
+ if param.TypeName() == arrayType && param.ItemsTypeName() == "" {
res.AddErrors(arrayInParamRequiresItemsMsg(param.Name, op.ID))
continue
}
- if param.In != "body" {
+ if param.In != swaggerBody {
if param.Items != nil {
items := param.Items
- for items.TypeName() == "array" {
+ for items.TypeName() == arrayType {
if items.ItemsTypeName() == "" {
res.AddErrors(arrayInParamRequiresItemsMsg(param.Name, op.ID))
break
@@ -374,7 +379,7 @@ func (s *SpecValidator) validateItems() *Result {
for _, resp := range responses {
// Response headers with array
for hn, hv := range resp.Headers {
- if hv.TypeName() == "array" && hv.ItemsTypeName() == "" {
+ if hv.TypeName() == arrayType && hv.ItemsTypeName() == "" {
res.AddErrors(arrayInHeaderRequiresItemsMsg(hn, op.ID))
}
}
@@ -390,7 +395,7 @@ func (s *SpecValidator) validateItems() *Result {
// Verifies constraints on array type
func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID string) *Result {
res := new(Result)
- if !schema.Type.Contains("array") {
+ if !schema.Type.Contains(arrayType) {
return res
}
@@ -451,6 +456,7 @@ func (s *SpecValidator) validateReferenced() *Result {
return &res
}
+// nolint: dupl
func (s *SpecValidator) validateReferencedParameters() *Result {
// Each referenceable definition should have references.
params := s.spec.Spec().Parameters
@@ -463,9 +469,7 @@ func (s *SpecValidator) validateReferencedParameters() *Result {
expected["#/parameters/"+jsonpointer.Escape(k)] = struct{}{}
}
for _, k := range s.analyzer.AllParameterReferences() {
- if _, ok := expected[k]; ok {
- delete(expected, k)
- }
+ delete(expected, k)
}
if len(expected) == 0 {
@@ -478,6 +482,7 @@ func (s *SpecValidator) validateReferencedParameters() *Result {
return result
}
+// nolint: dupl
func (s *SpecValidator) validateReferencedResponses() *Result {
// Each referenceable definition should have references.
responses := s.spec.Spec().Responses
@@ -490,9 +495,7 @@ func (s *SpecValidator) validateReferencedResponses() *Result {
expected["#/responses/"+jsonpointer.Escape(k)] = struct{}{}
}
for _, k := range s.analyzer.AllResponseReferences() {
- if _, ok := expected[k]; ok {
- delete(expected, k)
- }
+ delete(expected, k)
}
if len(expected) == 0 {
@@ -505,6 +508,7 @@ func (s *SpecValidator) validateReferencedResponses() *Result {
return result
}
+// nolint: dupl
func (s *SpecValidator) validateReferencedDefinitions() *Result {
// Each referenceable definition must have references.
defs := s.spec.Spec().Definitions
@@ -517,9 +521,7 @@ func (s *SpecValidator) validateReferencedDefinitions() *Result {
expected["#/definitions/"+jsonpointer.Escape(k)] = struct{}{}
}
for _, k := range s.analyzer.AllDefinitionReferences() {
- if _, ok := expected[k]; ok {
- delete(expected, k)
- }
+ delete(expected, k)
}
if len(expected) == 0 {
@@ -624,98 +626,114 @@ func (s *SpecValidator) validateParameters() *Result {
rexGarbledPathSegment := mustCompileRegexp(`.*[{}\s]+.*`)
for method, pi := range s.analyzer.Operations() {
methodPaths := make(map[string]map[string]string)
- if pi != nil { // Safeguard
- for path, op := range pi {
- pathToAdd := pathHelp.stripParametersInPath(path)
+ for path, op := range pi {
+ pathToAdd := pathHelp.stripParametersInPath(path)
- // Warn on garbled path afer param stripping
- if rexGarbledPathSegment.MatchString(pathToAdd) {
- res.AddWarnings(pathStrippedParamGarbledMsg(pathToAdd))
- }
+ // Warn on garbled path afer param stripping
+ if rexGarbledPathSegment.MatchString(pathToAdd) {
+ res.AddWarnings(pathStrippedParamGarbledMsg(pathToAdd))
+ }
- // Check uniqueness of stripped paths
- if _, found := methodPaths[method][pathToAdd]; found {
+ // Check uniqueness of stripped paths
+ if _, found := methodPaths[method][pathToAdd]; found {
- // Sort names for stable, testable output
- if strings.Compare(path, methodPaths[method][pathToAdd]) < 0 {
- res.AddErrors(pathOverlapMsg(path, methodPaths[method][pathToAdd]))
- } else {
- res.AddErrors(pathOverlapMsg(methodPaths[method][pathToAdd], path))
- }
+ // Sort names for stable, testable output
+ if strings.Compare(path, methodPaths[method][pathToAdd]) < 0 {
+ res.AddErrors(pathOverlapMsg(path, methodPaths[method][pathToAdd]))
} else {
- if _, found := methodPaths[method]; !found {
- methodPaths[method] = map[string]string{}
- }
- methodPaths[method][pathToAdd] = path //Original non stripped path
-
+ res.AddErrors(pathOverlapMsg(methodPaths[method][pathToAdd], path))
}
+ } else {
+ if _, found := methodPaths[method]; !found {
+ methodPaths[method] = map[string]string{}
+ }
+ methodPaths[method][pathToAdd] = path //Original non stripped path
- var bodyParams []string
- var paramNames []string
- var hasForm, hasBody bool
+ }
- // Check parameters names uniqueness for operation
- // TODO: should be done after param expansion
- res.Merge(s.checkUniqueParams(path, method, op))
+ var bodyParams []string
+ var paramNames []string
+ var hasForm, hasBody bool
- for _, pr := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
- // Validate pattern regexp for parameters with a Pattern property
- if _, err := compileRegexp(pr.Pattern); err != nil {
- res.AddErrors(invalidPatternInParamMsg(op.ID, pr.Name, pr.Pattern))
- }
+ // Check parameters names uniqueness for operation
+ // TODO: should be done after param expansion
+ res.Merge(s.checkUniqueParams(path, method, op))
- // There must be at most one parameter in body: list them all
- if pr.In == "body" {
- bodyParams = append(bodyParams, fmt.Sprintf("%q", pr.Name))
- hasBody = true
- }
+ for _, pr := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
+ // Validate pattern regexp for parameters with a Pattern property
+ if _, err := compileRegexp(pr.Pattern); err != nil {
+ res.AddErrors(invalidPatternInParamMsg(op.ID, pr.Name, pr.Pattern))
+ }
- if pr.In == "path" {
- paramNames = append(paramNames, pr.Name)
- // Path declared in path must have the required: true property
- if !pr.Required {
- res.AddErrors(pathParamRequiredMsg(op.ID, pr.Name))
- }
- }
+ // There must be at most one parameter in body: list them all
+ if pr.In == swaggerBody {
+ bodyParams = append(bodyParams, fmt.Sprintf("%q", pr.Name))
+ hasBody = true
+ }
- if pr.In == "formData" {
- hasForm = true
+ if pr.In == "path" {
+ paramNames = append(paramNames, pr.Name)
+ // Path declared in path must have the required: true property
+ if !pr.Required {
+ res.AddErrors(pathParamRequiredMsg(op.ID, pr.Name))
}
}
- // In:formData and In:body are mutually exclusive
- if hasBody && hasForm {
- res.AddErrors(bothFormDataAndBodyMsg(op.ID))
+ if pr.In == "formData" {
+ hasForm = true
}
- // There must be at most one body param
- // Accurately report situations when more than 1 body param is declared (possibly unnamed)
- if len(bodyParams) > 1 {
- sort.Strings(bodyParams)
- res.AddErrors(multipleBodyParamMsg(op.ID, bodyParams))
+
+ if !(pr.Type == numberType || pr.Type == integerType) &&
+ (pr.Maximum != nil || pr.Minimum != nil || pr.MultipleOf != nil) {
+ // A non-numeric parameter has validation keywords for numeric instances (number and integer)
+ res.AddWarnings(parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type))
}
- // Check uniqueness of parameters in path
- paramsInPath := pathHelp.extractPathParams(path)
- for i, p := range paramsInPath {
- for j, q := range paramsInPath {
- if p == q && i > j {
- res.AddErrors(pathParamNotUniqueMsg(path, p, q))
- break
- }
- }
+ if !(pr.Type == stringType) &&
+ // A non-string parameter has validation keywords for strings
+ (pr.MaxLength != nil || pr.MinLength != nil || pr.Pattern != "") {
+ res.AddWarnings(parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type))
+ }
+
+ if !(pr.Type == arrayType) &&
+ // A non-array parameter has validation keywords for arrays
+ (pr.MaxItems != nil || pr.MinItems != nil || pr.UniqueItems) {
+ res.AddWarnings(parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type))
}
+ }
+
+ // In:formData and In:body are mutually exclusive
+ if hasBody && hasForm {
+ res.AddErrors(bothFormDataAndBodyMsg(op.ID))
+ }
+ // There must be at most one body param
+ // Accurately report situations when more than 1 body param is declared (possibly unnamed)
+ if len(bodyParams) > 1 {
+ sort.Strings(bodyParams)
+ res.AddErrors(multipleBodyParamMsg(op.ID, bodyParams))
+ }
- // Warns about possible malformed params in path
- rexGarbledParam := mustCompileRegexp(`{.*[{}\s]+.*}`)
- for _, p := range paramsInPath {
- if rexGarbledParam.MatchString(p) {
- res.AddWarnings(pathParamGarbledMsg(path, p))
+ // Check uniqueness of parameters in path
+ paramsInPath := pathHelp.extractPathParams(path)
+ for i, p := range paramsInPath {
+ for j, q := range paramsInPath {
+ if p == q && i > j {
+ res.AddErrors(pathParamNotUniqueMsg(path, p, q))
+ break
}
}
+ }
- // Match params from path vs params from params section
- res.Merge(s.validatePathParamPresence(path, paramsInPath, paramNames))
+ // Warns about possible malformed params in path
+ rexGarbledParam := mustCompileRegexp(`{.*[{}\s]+.*}`)
+ for _, p := range paramsInPath {
+ if rexGarbledParam.MatchString(p) {
+ res.AddWarnings(pathParamGarbledMsg(path, p))
+ }
}
+
+ // Match params from path vs params from params section
+ res.Merge(s.validatePathParamPresence(path, paramsInPath, paramNames))
}
}
return res