Skip to content

Commit 7597d76

Browse files
committed
Add ozzo string rule for checking if a value is a valid path parameter
1 parent d564f6f commit 7597d76

File tree

4 files changed

+44
-7
lines changed

4 files changed

+44
-7
lines changed

utils/url/url.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type PathSegmentMatcherFunc = func(segmentA, segmentB string) (match bool, err e
2525
// ValidatePathParameter checks whether a path parameter is valid. An error is returned if it is invalid.
2626
// Version 3.1.0 of the OpenAPI spec provides some guidance for path parameter values (see https://spec.openapis.org/oas/v3.1.0.html#path-templating)
2727
func ValidatePathParameter(parameter string) error {
28-
if !IsPathParameter(parameter) {
28+
if !MatchesPathParameterSyntax(parameter) {
2929
return commonerrors.Newf(commonerrors.ErrInvalid, "parameter %q must not be empty, cannot contain only whitespaces, have a length greater than or equal to three, start with an opening brace, and end with a closing brace", parameter)
3030
}
3131

@@ -41,8 +41,8 @@ func ValidatePathParameter(parameter string) error {
4141
return nil
4242
}
4343

44-
// IsPathParameter checks whether the parameter string is a path parameter as described by the OpenAPI spec (see https://spec.openapis.org/oas/v3.0.0.html#path-templating).
45-
func IsPathParameter(parameter string) bool {
44+
// MatchesPathParameterSyntax checks whether the parameter string matches the syntax for a path parameter as described by the OpenAPI spec (see https://spec.openapis.org/oas/v3.0.0.html#path-templating).
45+
func MatchesPathParameterSyntax(parameter string) bool {
4646
if reflection.IsEmpty(parameter) {
4747
return false
4848
}
@@ -80,7 +80,7 @@ func BasicEqualityPathSegmentMatcher(segmentA, segmentB string) (match bool, err
8080

8181
// BasicEqualityPathSegmentWithParamMatcher is a PathSegmentMatcherFunc that is similar to BasicEqualityPathSegmentMatcher but accounts for path parameter segments.
8282
func BasicEqualityPathSegmentWithParamMatcher(segmentA, segmentB string) (match bool, err error) {
83-
if IsPathParameter(segmentA) {
83+
if MatchesPathParameterSyntax(segmentA) {
8484
if errValidatePathASeg := ValidatePathParameter(segmentA); errValidatePathASeg != nil {
8585
err = commonerrors.WrapErrorf(commonerrors.ErrInvalid, errValidatePathASeg, "an error occurred while validating path parameter %q", segmentA)
8686
return
@@ -90,7 +90,7 @@ func BasicEqualityPathSegmentWithParamMatcher(segmentA, segmentB string) (match
9090
return
9191
}
9292

93-
if IsPathParameter(segmentB) {
93+
if MatchesPathParameterSyntax(segmentB) {
9494
if errValidatePathBSeg := ValidatePathParameter(segmentB); errValidatePathBSeg != nil {
9595
err = commonerrors.WrapErrorf(commonerrors.ErrInvalid, errValidatePathBSeg, "an error occurred while validating path parameter %q", segmentB)
9696
return

utils/url/url_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"github.com/ARM-software/golang-utils/utils/commonerrors/errortest"
1111
)
1212

13-
func TestUrl_IsPathParameter(t *testing.T) {
13+
func TestUrl_MatchesPathParameterSyntax(t *testing.T) {
1414
tests := []struct {
1515
name string
1616
parameter string
@@ -71,7 +71,7 @@ func TestUrl_IsPathParameter(t *testing.T) {
7171
for i := range tests {
7272
test := tests[i]
7373
t.Run(test.name, func(t *testing.T) {
74-
assert.Equal(t, test.result, IsPathParameter(test.parameter))
74+
assert.Equal(t, test.result, MatchesPathParameterSyntax(test.parameter))
7575
})
7676
}
7777
}

utils/validation/rules.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/ARM-software/golang-utils/utils/commonerrors"
1111
"github.com/ARM-software/golang-utils/utils/encoding/base64"
12+
"github.com/ARM-software/golang-utils/utils/url"
1213
)
1314

1415
// IsPort validates whether a value is a port using is.Port from github.com/go-ozzo/ozzo-validation/v4.
@@ -41,3 +42,11 @@ func isPort(vRaw any) (err error) {
4142

4243
// IsBase64 validates whether a value is a base64 encoded string. It is similar to is.Base64 but more generic and robust although less performant.
4344
var IsBase64 = validation.NewStringRuleWithError(base64.IsEncoded, is.ErrBase64)
45+
46+
// IsPathParameter validates whether a value is a valid path parameter of a url.
47+
var IsPathParameter = validation.NewStringRule(isValidPathParameter, "invalid path parameter")
48+
49+
func isValidPathParameter(value string) bool {
50+
err := url.ValidatePathParameter(value)
51+
return err == nil
52+
}

utils/validation/rules_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,31 @@ func TestIsBase64Encoded(t *testing.T) {
9797
})
9898
}
9999
}
100+
101+
func TestIsPathParameter(t *testing.T) {
102+
tests := []struct {
103+
input string
104+
expected bool
105+
}{
106+
{"{abc}", true},
107+
{"abc}", false},
108+
{"{abc", false},
109+
{"abc", false},
110+
{"{abc$123.zzz~999}", true},
111+
{"{abc%5F1}", true}, // unescaped as '{abc_1}'
112+
{"{abc#123}", false},
113+
{" ", false},
114+
}
115+
116+
for i := range tests {
117+
test := tests[i]
118+
t.Run(test.input, func(t *testing.T) {
119+
err := validation.Validate(test.input, IsPathParameter)
120+
if test.expected {
121+
require.NoError(t, err)
122+
} else {
123+
errortest.AssertErrorDescription(t, err, "invalid path parameter")
124+
}
125+
})
126+
}
127+
}

0 commit comments

Comments
 (0)