feat(api): prefer absolute OpenAPI servers

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-01 17:24:36 +00:00
parent da9bb918f7
commit 5b59a1dd10
2 changed files with 67 additions and 2 deletions

View file

@ -231,8 +231,13 @@ func (c *OpenAPIClient) loadSpec() error {
}
}
if c.baseURL == "" && len(c.servers) > 0 {
c.baseURL = c.servers[0]
if c.baseURL == "" {
for _, server := range c.servers {
if isAbsoluteBaseURL(server) {
c.baseURL = server
break
}
}
}
return nil
@ -453,3 +458,11 @@ func appendQueryValue(query url.Values, key string, value any) {
query.Add(key, fmt.Sprint(value))
}
func isAbsoluteBaseURL(raw string) bool {
u, err := url.Parse(raw)
if err != nil {
return false
}
return u.Scheme != "" && u.Host != ""
}

View file

@ -257,6 +257,58 @@ paths:
}
}
func TestOpenAPIClient_Good_UsesFirstAbsoluteServer(t *testing.T) {
errCh := make(chan error, 1)
mux := http.NewServeMux()
mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
errCh <- fmt.Errorf("expected GET, got %s", r.Method)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"success":true,"data":{"message":"hello"}}`))
})
srv := httptest.NewServer(mux)
defer srv.Close()
specPath := writeTempSpec(t, `openapi: 3.1.0
info:
title: Test API
version: 1.0.0
servers:
- url: /
- url: `+srv.URL+`
paths:
/hello:
get:
operationId: get_hello
`)
client := api.NewOpenAPIClient(
api.WithSpec(specPath),
)
result, err := client.Call("get_hello", nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
select {
case err := <-errCh:
t.Fatal(err)
default:
}
hello, ok := result.(map[string]any)
if !ok {
t.Fatalf("expected map result, got %T", result)
}
if hello["message"] != "hello" {
t.Fatalf("expected message=hello, got %#v", hello["message"])
}
}
func TestOpenAPIClient_Bad_MissingOperation(t *testing.T) {
specPath := writeTempSpec(t, `openapi: 3.1.0
info: