Skip to content

Commit

Permalink
Merge pull request #714 from froz42/main
Browse files Browse the repository at this point in the history
fix: implement findRelativeRessourcePath function to fix PatchResourc…
  • Loading branch information
danielgtaylor authored Feb 13, 2025
2 parents f9ffb6a + 2a47997 commit af68f0e
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
35 changes: 33 additions & 2 deletions autopatch/autopatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,10 @@ func PatchResource(api huma.API, path *huma.PathItem) {
return
}

resourcePath := findRelativeResourcePath(ctx.URL().Path, put.Path)

// Perform the get!
origReq, err := http.NewRequest(http.MethodGet, ctx.URL().Path, nil)
origReq, err := http.NewRequest(http.MethodGet, resourcePath, nil)
if err != nil {
huma.WriteErr(api, ctx, http.StatusInternalServerError, "Unable to get resource", err)
return
Expand Down Expand Up @@ -281,7 +283,7 @@ func PatchResource(api huma.API, path *huma.PathItem) {
}

// Write the updated data back to the server!
putReq, err := http.NewRequest(http.MethodPut, ctx.URL().Path, bytes.NewReader(patched))
putReq, err := http.NewRequest(http.MethodPut, resourcePath, bytes.NewReader(patched))
if err != nil {
huma.WriteErr(api, ctx, http.StatusInternalServerError, "Unable to put modified resource", err)
return
Expand Down Expand Up @@ -400,3 +402,32 @@ func makeOptionalSchema(s *huma.Schema) *huma.Schema {

return optionalSchema
}

// This function help to find the relative path of the resource to patch
// this allow to handle potential prefix in the path
// for example if the requestPath is /api/v1/user/1 and the put path is /user/{id}
// the function will return /user/1
func findRelativeResourcePath(requestPath string, putPath string) string {
putPathParts := strings.Split(putPath, "/")
// if the path is not deep enough, we return the original path
if len(putPathParts) < 2 {
return requestPath
}
wantedPrefix := putPathParts[1]
workingPath := requestPath
for !strings.HasPrefix(workingPath, wantedPrefix) {
// we find the next /
slashIndex := strings.Index(workingPath, "/")
// if we don't have a / anymore, we return the original path
if slashIndex == -1 {
return requestPath
}
// we remove till the next /
workingPath = workingPath[slashIndex+1:]
// if we reach the end of the path, we return the original path
if workingPath == "" {
return requestPath
}
}
return "/" + workingPath
}
40 changes: 40 additions & 0 deletions autopatch/autopatch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,43 @@ func TestMakeOptionalSchemaNestedSchemas(t *testing.T) {
assert.Empty(t, optionalNestedSchema.Required)
assert.Empty(t, optionalNestedSchema.Properties["nested"].Required)
}

type findRelativeResourcePathTest struct {
requestPath string
putPath string
expected string
}

func TestFindRelativeResourcePath(t *testing.T) {
tests := []findRelativeResourcePathTest{
{
requestPath: "/things/test",
putPath: "/things/{id}",
expected: "/things/test",
},
{
requestPath: "/api/things/test",
putPath: "/things/{id}",
expected: "/things/test",
},
{
requestPath: "/test",
putPath: "/{id}",
expected: "/test",
},
{
requestPath: "/api/v1/super/things/test",
putPath: "/things/{id}",
expected: "/things/test",
},
{
requestPath: "/api/v1/test",
putPath: "{id}",
expected: "/api/v1/test", // we check that we falback to the request path if unsupported
},
}

for _, test := range tests {
assert.Equal(t, test.expected, findRelativeResourcePath(test.requestPath, test.putPath))
}
}

0 comments on commit af68f0e

Please sign in to comment.