@@ -93,36 +93,38 @@ type RequestStatus string
93
93
94
94
// Statuses of the request, all are false-y except StatusOk and StatusOkAndIgnore
95
95
const (
96
- VersionNotFound RequestStatus = "Version information not found"
97
- VersionDoesNotExist RequestStatus = "This API version does not seem to exist"
98
- VersionWhiteListStatusNotFound RequestStatus = "WhiteListStatus for path not found"
99
- VersionExpired RequestStatus = "Api Version has expired, please check documentation or contact administrator"
100
- APIExpired RequestStatus = "API has expired, please check documentation or contact administrator"
101
- EndPointNotAllowed RequestStatus = "Requested endpoint is forbidden"
102
- StatusOkAndIgnore RequestStatus = "Everything OK, passing and not filtering"
103
- StatusOk RequestStatus = "Everything OK, passing"
104
- StatusCached RequestStatus = "Cached path"
105
- StatusTransform RequestStatus = "Transformed path"
106
- StatusTransformResponse RequestStatus = "Transformed response"
107
- StatusTransformJQ RequestStatus = "Transformed path with JQ"
108
- StatusTransformJQResponse RequestStatus = "Transformed response with JQ"
109
- StatusHeaderInjected RequestStatus = "Header injected"
110
- StatusMethodTransformed RequestStatus = "Method Transformed"
111
- StatusHeaderInjectedResponse RequestStatus = "Header injected on response"
112
- StatusRedirectFlowByReply RequestStatus = "Exceptional action requested, redirecting flow!"
113
- StatusHardTimeout RequestStatus = "Hard Timeout enforced on path"
114
- StatusCircuitBreaker RequestStatus = "Circuit breaker enforced"
115
- StatusURLRewrite RequestStatus = "URL Rewritten"
116
- StatusVirtualPath RequestStatus = "Virtual Endpoint"
117
- StatusRequestSizeControlled RequestStatus = "Request Size Limited"
118
- StatusRequestTracked RequestStatus = "Request Tracked"
119
- StatusRequestNotTracked RequestStatus = "Request Not Tracked"
120
- StatusValidateJSON RequestStatus = "Validate JSON"
121
- StatusValidateRequest RequestStatus = "Validate Request"
122
- StatusInternal RequestStatus = "Internal path"
123
- StatusGoPlugin RequestStatus = "Go plugin"
124
- StatusPersistGraphQL RequestStatus = "Persist GraphQL"
125
- StatusRateLimit RequestStatus = "Rate Limited"
96
+ VersionNotFound RequestStatus = "Version information not found"
97
+ VersionDoesNotExist RequestStatus = "This API version does not seem to exist"
98
+ VersionWhiteListStatusNotFound RequestStatus = "WhiteListStatus for path not found"
99
+ VersionExpired RequestStatus = "Api Version has expired, please check documentation or contact administrator"
100
+ VersionDefaultForNotVersionedNotFound RequestStatus = "No default API version for this non-versioned API found"
101
+ VersionAmbiguousDefault RequestStatus = "Ambiguous default API version for this non-versioned API"
102
+ APIExpired RequestStatus = "API has expired, please check documentation or contact administrator"
103
+ EndPointNotAllowed RequestStatus = "Requested endpoint is forbidden"
104
+ StatusOkAndIgnore RequestStatus = "Everything OK, passing and not filtering"
105
+ StatusOk RequestStatus = "Everything OK, passing"
106
+ StatusCached RequestStatus = "Cached path"
107
+ StatusTransform RequestStatus = "Transformed path"
108
+ StatusTransformResponse RequestStatus = "Transformed response"
109
+ StatusTransformJQ RequestStatus = "Transformed path with JQ"
110
+ StatusTransformJQResponse RequestStatus = "Transformed response with JQ"
111
+ StatusHeaderInjected RequestStatus = "Header injected"
112
+ StatusMethodTransformed RequestStatus = "Method Transformed"
113
+ StatusHeaderInjectedResponse RequestStatus = "Header injected on response"
114
+ StatusRedirectFlowByReply RequestStatus = "Exceptional action requested, redirecting flow!"
115
+ StatusHardTimeout RequestStatus = "Hard Timeout enforced on path"
116
+ StatusCircuitBreaker RequestStatus = "Circuit breaker enforced"
117
+ StatusURLRewrite RequestStatus = "URL Rewritten"
118
+ StatusVirtualPath RequestStatus = "Virtual Endpoint"
119
+ StatusRequestSizeControlled RequestStatus = "Request Size Limited"
120
+ StatusRequestTracked RequestStatus = "Request Tracked"
121
+ StatusRequestNotTracked RequestStatus = "Request Not Tracked"
122
+ StatusValidateJSON RequestStatus = "Validate JSON"
123
+ StatusValidateRequest RequestStatus = "Validate Request"
124
+ StatusInternal RequestStatus = "Internal path"
125
+ StatusGoPlugin RequestStatus = "Go plugin"
126
+ StatusPersistGraphQL RequestStatus = "Persist GraphQL"
127
+ StatusRateLimit RequestStatus = "Rate Limited"
126
128
)
127
129
128
130
type EndPointCacheMeta struct {
@@ -1664,10 +1666,15 @@ func (a *APISpec) Version(r *http.Request) (*apidef.VersionInfo, RequestStatus)
1664
1666
} else {
1665
1667
// Are we versioned?
1666
1668
if a .VersionData .NotVersioned {
1667
- // Get the first one in the list
1668
- for _ , v := range a .VersionData .Versions {
1669
- version = v
1670
- break
1669
+ ambiguous := a .CheckForAmbiguousDefaultVersions ()
1670
+ if ambiguous {
1671
+ return nil , VersionAmbiguousDefault
1672
+ }
1673
+
1674
+ ok := false
1675
+ version , ok = a .GetSingleOrDefaultVersion ()
1676
+ if ! ok {
1677
+ return nil , VersionDefaultForNotVersionedNotFound
1671
1678
}
1672
1679
} else {
1673
1680
// Extract Version Info
@@ -1701,6 +1708,57 @@ func (a *APISpec) Version(r *http.Request) (*apidef.VersionInfo, RequestStatus)
1701
1708
return & version , StatusOk
1702
1709
}
1703
1710
1711
+ // GetSingleOrDefaultVersion determines and returns a single version or the default version if only one or a default exists.
1712
+ // Returns versionInfo and a boolean indicating success or failure.
1713
+ func (a * APISpec ) GetSingleOrDefaultVersion () (versionInfo apidef.VersionInfo , ok bool ) {
1714
+ // If only one version exists, we can safely return this one
1715
+ if len (a .VersionData .Versions ) == 1 {
1716
+ for _ , v := range a .VersionData .Versions {
1717
+ return v , true
1718
+ }
1719
+ }
1720
+
1721
+ // Now we check if a default version is defined and will look for it, when NotVersioned is set to false.
1722
+ // Otherwise, we skip this check.
1723
+ if ! a .VersionData .NotVersioned && a .VersionData .DefaultVersion != "" {
1724
+ versionInfo , ok = a .VersionData .Versions [a .VersionData .DefaultVersion ]
1725
+ return versionInfo , ok
1726
+ }
1727
+
1728
+ // If no default version is defined, we try to find one named "Default", "default" or ""
1729
+ if versionInfo , ok = a .VersionData .Versions ["Default" ]; ok {
1730
+ return versionInfo , ok
1731
+ }
1732
+
1733
+ if versionInfo , ok = a .VersionData .Versions ["default" ]; ok {
1734
+ return versionInfo , ok
1735
+ }
1736
+
1737
+ if versionInfo , ok = a .VersionData .Versions ["" ]; ok {
1738
+ return versionInfo , ok
1739
+ }
1740
+
1741
+ // If we reach this point, we tried everything to find a default version and failed
1742
+ return apidef.VersionInfo {}, false
1743
+ }
1744
+
1745
+ // CheckForAmbiguousDefaultVersions checks if there are multiple ambiguous default versions in the version data.
1746
+ func (a * APISpec ) CheckForAmbiguousDefaultVersions () bool {
1747
+ foundDefaultVersions := 0
1748
+ for key := range a .VersionData .Versions {
1749
+ switch key {
1750
+ case "Default" :
1751
+ fallthrough
1752
+ case "default" :
1753
+ fallthrough
1754
+ case "" :
1755
+ foundDefaultVersions ++
1756
+ }
1757
+ }
1758
+
1759
+ return foundDefaultVersions > 1
1760
+ }
1761
+
1704
1762
// StripListenPath will strip the listen path from the URL, keeping version in tact.
1705
1763
func (a * APISpec ) StripListenPath (reqPath string ) string {
1706
1764
return httputil .StripListenPath (a .Proxy .ListenPath , reqPath )
0 commit comments