Skip to content

Commit 156dec4

Browse files
fix: update findOperations to check for endpoint name for parameterised endpoints
1 parent 42f5625 commit 156dec4

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

rolling-shutter/keyper/kproapi/middleware.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package kproapi
33
import (
44
"encoding/json"
55
"net/http"
6+
"regexp"
7+
"strings"
68

79
"github.com/getkin/kin-openapi/openapi3"
810
)
@@ -34,8 +36,23 @@ func shouldEnableEndpoint(operation *openapi3.Operation, enableWriteOperations b
3436

3537
// findOperation looks up the OpenAPI operation for the given path and method.
3638
func findOperation(spec *openapi3.T, path string, method string) *openapi3.Operation {
37-
pathItem := spec.Paths.Find(path)
39+
pathItem := spec.Paths.Find(path) // first try to find the path in the spec
3840
if pathItem == nil {
41+
for specPath, pItem := range spec.Paths { // fallback for path containing parameters
42+
rePath := "^" + regexp.QuoteMeta(specPath)
43+
rePath = strings.ReplaceAll(rePath, `\{`, "{")
44+
rePath = strings.ReplaceAll(rePath, `\}`, "}")
45+
rePath = regexp.MustCompile(`\{[^/]+\}`).ReplaceAllString(rePath, `[^/]+`)
46+
rePath += "$"
47+
48+
if matched, _ := regexp.MatchString(rePath, path); matched {
49+
pathItem = pItem
50+
break
51+
}
52+
}
53+
}
54+
55+
if pathItem == nil { // if no path is found still, return nil
3956
return nil
4057
}
4158

rolling-shutter/keyper/kproapi/middleware_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,58 @@ func TestFindOperation(t *testing.T) {
182182
}
183183
}
184184

185+
func TestFindOperation_ParameterizedPaths(t *testing.T) {
186+
spec := &openapi3.T{
187+
Paths: openapi3.Paths{
188+
"/test/{id}": &openapi3.PathItem{
189+
Get: &openapi3.Operation{},
190+
},
191+
"/tests/{id}/items/{name}": &openapi3.PathItem{
192+
Post: &openapi3.Operation{},
193+
},
194+
},
195+
}
196+
197+
tests := []struct {
198+
name string
199+
path string
200+
method string
201+
want *openapi3.Operation
202+
}{
203+
{
204+
name: "match single parameterized path",
205+
path: "/test/123",
206+
method: http.MethodGet,
207+
want: spec.Paths.Find("/test/{id}").Get,
208+
},
209+
{
210+
name: "match nested parameterized path",
211+
path: "/tests/123/items/xyz456",
212+
method: http.MethodPost,
213+
want: spec.Paths.Find("/tests/{id}/items/{name}").Post,
214+
},
215+
{
216+
name: "no match for wrong structure",
217+
path: "/tests/123/items", // missing /{name}
218+
method: http.MethodPost,
219+
want: nil,
220+
},
221+
{
222+
name: "non-existent parameterized path",
223+
path: "/unknown/123",
224+
method: http.MethodGet,
225+
want: nil,
226+
},
227+
}
228+
229+
for _, tt := range tests {
230+
t.Run(tt.name, func(t *testing.T) {
231+
got := findOperation(spec, tt.path, tt.method)
232+
assert.Equal(t, tt.want, got)
233+
})
234+
}
235+
}
236+
185237
func TestConfigMiddleware(t *testing.T) {
186238
// Create a test spec with both read-only and write operations
187239
spec := &openapi3.T{

0 commit comments

Comments
 (0)