fix(client): promote declared query params on all methods

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-01 21:19:45 +00:00
parent db9daadbce
commit 4ce697189a
2 changed files with 92 additions and 15 deletions

View file

@ -342,22 +342,21 @@ func (c *OpenAPIClient) buildURL(op openAPIOperation, params map[string]any) (st
appendQueryValue(query, key, value)
}
}
if op.method == http.MethodGet || (op.method == http.MethodHead && !op.hasRequestBody) {
for key, value := range params {
if key == "path" || key == "body" || key == "query" || key == "header" || key == "cookie" {
continue
}
if containsString(pathKeys, key) {
continue
}
if operationParameterLocation(op, key) == "header" || operationParameterLocation(op, key) == "cookie" {
continue
}
if _, exists := query[key]; exists {
continue
}
appendQueryValue(query, key, value)
for key, value := range params {
if key == "path" || key == "body" || key == "query" || key == "header" || key == "cookie" {
continue
}
if containsString(pathKeys, key) {
continue
}
location := operationParameterLocation(op, key)
if location != "query" && !(location == "" && (op.method == http.MethodGet || (op.method == http.MethodHead && !op.hasRequestBody))) {
continue
}
if _, exists := query[key]; exists {
continue
}
appendQueryValue(query, key, value)
}
if encoded := query.Encode(); encoded != "" {

View file

@ -257,6 +257,84 @@ paths:
}
}
func TestOpenAPIClient_Good_UsesTopLevelQueryParametersOnPost(t *testing.T) {
errCh := make(chan error, 1)
mux := http.NewServeMux()
mux.HandleFunc("/submit", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
errCh <- fmt.Errorf("expected POST, got %s", r.Method)
w.WriteHeader(http.StatusInternalServerError)
return
}
if got := r.URL.Query().Get("verbose"); got != "true" {
errCh <- fmt.Errorf("expected query verbose=true, got %q", got)
w.WriteHeader(http.StatusInternalServerError)
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
errCh <- fmt.Errorf("read body: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if string(body) != `{"name":"Ada"}` {
errCh <- fmt.Errorf("expected JSON body {\"name\":\"Ada\"}, got %q", string(body))
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"success":true,"data":{"ok":true}}`))
})
srv := httptest.NewServer(mux)
defer srv.Close()
specPath := writeTempSpec(t, `openapi: 3.1.0
info:
title: Test API
version: 1.0.0
paths:
/submit:
post:
operationId: submit_item
requestBody:
required: true
content:
application/json:
schema:
type: object
parameters:
- name: verbose
in: query
`)
client := api.NewOpenAPIClient(
api.WithSpec(specPath),
api.WithBaseURL(srv.URL),
)
result, err := client.Call("submit_item", map[string]any{
"verbose": true,
"name": "Ada",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
select {
case err := <-errCh:
t.Fatal(err)
default:
}
decoded, ok := result.(map[string]any)
if !ok {
t.Fatalf("expected map result, got %T", result)
}
if okValue, ok := decoded["ok"].(bool); !ok || !okValue {
t.Fatalf("expected ok=true, got %#v", decoded["ok"])
}
}
func TestOpenAPIClient_Good_UsesHeaderAndCookieParameters(t *testing.T) {
errCh := make(chan error, 1)
mux := http.NewServeMux()