Skip to content

Commit

Permalink
Allows base paths to include query parameters (#209)
Browse files Browse the repository at this point in the history
* Allows base paths to include query parameters

This is a test case and a fix for #207.

When the base path of an operation contains a query string, those parameters are:

1. extracted before appending any path parameters to the path
2. merged with the query parameters

In the case of a conflict between the parameters passed in the API call and the ones declared in the base path, the former prevails. This gives the end control to clients.

Signed-off-by: Julien Silland <julien@soliton.io>

* fixup! Allows base paths to include query parameters

Signed-off-by: Julien Silland <julien@soliton.io>

* fixup! Allows base paths to include query parameters

Signed-off-by: Julien Silland <julien@soliton.io>

* fixup! Allows base paths to include query parameters

Signed-off-by: Julien Silland <julien@soliton.io>

* fixup! Allows base paths to include query parameters

Signed-off-by: Julien Silland <julien@soliton.io>
  • Loading branch information
jsilland committed Aug 25, 2021
1 parent 60c8ebd commit 872b746
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
25 changes: 24 additions & 1 deletion client/request.go
Expand Up @@ -278,7 +278,17 @@ DoneChoosingBodySource:
if r.pathPattern != "" && r.pathPattern != "/" && r.pathPattern[len(r.pathPattern)-1] == '/' {
reinstateSlash = true
}
urlPath := path.Join(basePath, r.pathPattern)

// In case the basePath includes hardcoded query parameters, parse those out before
// constructing the final path. The parameters themselves will be merged with the
// ones set by the client, with the priority given to the latter.
basePathURL, err := url.Parse(basePath)
if err != nil {
return nil, err
}
basePathQueryParams := basePathURL.Query()

urlPath := path.Join(basePathURL.Path, r.pathPattern)
for k, v := range r.pathParams {
urlPath = strings.Replace(urlPath, "{"+k+"}", url.PathEscape(v), -1)
}
Expand All @@ -291,6 +301,19 @@ DoneChoosingBodySource:
return nil, err
}

originalParams := r.GetQueryParams()

// Merge the query parameters extracted from the basePath with the ones set by
// the client in this struct. In case of conflict, the client wins.
for k, v := range basePathQueryParams {
_, present := originalParams[k]
if !present {
if err = r.SetQueryParam(k, v...); err != nil {
return nil, err
}
}
}

req.URL.RawQuery = r.query.Encode()
req.Header = r.header

Expand Down
33 changes: 33 additions & 0 deletions client/request_test.go
Expand Up @@ -517,6 +517,39 @@ func TestBuildRequest_BuildHTTP_EscapedPath(t *testing.T) {
}
}

func TestBuildRequest_BuildHTTP_BasePathWithParameters(t *testing.T) {
reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
_ = req.SetBodyParam(nil)
_ = req.SetQueryParam("hello", "world")
_ = req.SetPathParam("id", "1234")
return nil
})
r, _ := newRequest("POST", "/flats/{id}/", reqWrtr)

req, err := r.BuildHTTP(runtime.JSONMime, "/basepath?foo=bar", testProducers, nil)
if assert.NoError(t, err) && assert.NotNil(t, req) {
assert.Equal(t, "world", req.URL.Query().Get("hello"))
assert.Equal(t, "bar", req.URL.Query().Get("foo"))
assert.Equal(t, "/basepath/flats/1234/", req.URL.Path)
}
}

func TestBuildRequest_BuildHTTP_BasePathWithConflictingParameters(t *testing.T) {
reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
_ = req.SetBodyParam(nil)
_ = req.SetQueryParam("hello", "world")
_ = req.SetPathParam("id", "1234")
return nil
})
r, _ := newRequest("POST", "/flats/{id}/", reqWrtr)

req, err := r.BuildHTTP(runtime.JSONMime, "/basepath?hello=kitty", testProducers, nil)
if assert.NoError(t, err) && assert.NotNil(t, req) {
assert.Equal(t, "world", req.URL.Query().Get("hello"))
assert.Equal(t, "/basepath/flats/1234/", req.URL.Path)
}
}

type testReqFn func(*testing.T, *http.Request)

type testRoundTripper struct {
Expand Down

0 comments on commit 872b746

Please sign in to comment.