Skip to content

Commit

Permalink
Merge pull request #157 from dadgar/master
Browse files Browse the repository at this point in the history
Validation Option to disable strict path parameter uniqueness validation
  • Loading branch information
casualjim committed Nov 20, 2023
2 parents 348543c + 99afba0 commit 194d97e
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 20 deletions.
2 changes: 1 addition & 1 deletion doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Reported as errors:
[x] definition can't declare a property that's already defined by one of its ancestors
[x] definition's ancestor can't be a descendant of the same model
[x] path uniqueness: each api path should be non-verbatim (account for path param names) unique per method
[x] path uniqueness: each api path should be non-verbatim (account for path param names) unique per method. Validation can be laxed by disabling StrictPathParamUniqueness.
[x] each security reference should contain only unique scopes
[x] each security scope in a security definition should be unique
[x] parameters in path must be unique
Expand Down
20 changes: 19 additions & 1 deletion options.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,28 @@ import "sync"
// NOTE: other options might be needed, for example a go-swagger specific mode.
type Opts struct {
ContinueOnErrors bool // true: continue reporting errors, even if spec is invalid

// StrictPathParamUniqueness enables a strict validation of paths that include
// path parameters. When true, it will enforce that for each method, the path
// is unique, regardless of path parameters such that GET:/petstore/{id} and
// GET:/petstore/{pet} anre considered duplicate paths.
//
// Consider disabling if path parameters can include slashes such as
// GET:/v1/{shelve} and GET:/v1/{book}, where the IDs are "shelve/*" and
// /"shelve/*/book/*" respectively.
StrictPathParamUniqueness bool
}

var (
defaultOpts = Opts{ContinueOnErrors: false} // default is to stop validation on errors
defaultOpts = Opts{
// default is to stop validation on errors
ContinueOnErrors: false,

// StrictPathParamUniqueness is defaulted to true. This maintains existing
// behavior.
StrictPathParamUniqueness: true,
}

defaultOptsMutex = &sync.Mutex{}
)

Expand Down
38 changes: 20 additions & 18 deletions spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ func (s *SpecValidator) validateRequiredProperties(path, in string, v *spec.Sche
func (s *SpecValidator) validateParameters() *Result {
// - for each method, path is unique, regardless of path parameters
// e.g. GET:/petstore/{id}, GET:/petstore/{pet}, GET:/petstore are
// considered duplicate paths
// considered duplicate paths, if StrictPathParamUniqueness is enabled.
// - each parameter should have a unique `name` and `type` combination
// - each operation should have only 1 parameter of type body
// - there must be at most 1 parameter in body
Expand All @@ -626,28 +626,30 @@ func (s *SpecValidator) validateParameters() *Result {
for method, pi := range s.expandedAnalyzer().Operations() {
methodPaths := make(map[string]map[string]string)
for path, op := range pi {
pathToAdd := pathHelp.stripParametersInPath(path)
if s.Options.StrictPathParamUniqueness {
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]))
// 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))
}
} else {
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
if _, found := methodPaths[method]; !found {
methodPaths[method] = map[string]string{}
}
methodPaths[method][pathToAdd] = path // Original non stripped path

}
}

var bodyParams []string
Expand Down
5 changes: 5 additions & 0 deletions spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,11 @@ func TestSpec_ValidateParameters(t *testing.T) {
assert.Len(t, res.Errors, 1)
assert.Contains(t, res.Errors[0].Error(), "overlaps with")

// Disable strict path param uniqueness and ensure there is no error
validator.Options.StrictPathParamUniqueness = false
res = validator.validateParameters()
assert.Empty(t, res.Errors)

doc, _ = loads.Analyzed(PetStoreJSONMessage, "")
validator = NewSpecValidator(spec.MustLoadSwagger20Schema(), strfmt.Default)
validator.spec = doc
Expand Down

0 comments on commit 194d97e

Please sign in to comment.