diff --git a/options.go b/options.go index 5f67acf..6b576c6 100644 --- a/options.go +++ b/options.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "net/url" + "strings" "time" ) @@ -11,6 +12,10 @@ import ( type Option func(*Client) // WithBaseURL overrides the API base URL (default https://api.flashcat.cloud). +// A path prefix is preserved: with "https://gateway.example.com/api", requests +// go to /api/. The path is normalized to end with "/" so that +// relative resolution appends endpoint paths instead of replacing the last +// path segment. func WithBaseURL(raw string) Option { parsed, err := url.Parse(raw) return func(c *Client) { @@ -18,6 +23,9 @@ func WithBaseURL(raw string) Option { c.optionErr = fmt.Errorf("flashduty: invalid base URL %q: %w", raw, err) return } + if !strings.HasSuffix(parsed.Path, "/") { + parsed.Path += "/" + } c.BaseURL = parsed } } diff --git a/options_test.go b/options_test.go index 12cdab4..1c3af01 100644 --- a/options_test.go +++ b/options_test.go @@ -18,7 +18,7 @@ func TestNewClientDefaultsAndOptions(t *testing.T) { if err != nil { t.Fatal(err) } - if c.BaseURL.String() != "https://example.test" { + if c.BaseURL.String() != "https://example.test/" { t.Fatalf("BaseURL = %s", c.BaseURL) } if c.UserAgent != "ua/1" { @@ -35,6 +35,34 @@ func TestWithBaseURLInvalidReturnsError(t *testing.T) { } } +func TestWithBaseURLPreservesPathPrefix(t *testing.T) { + for _, tc := range []struct { + base string + want string + }{ + {"https://example.test", "https://example.test/rum/data/query"}, + {"https://example.test/", "https://example.test/rum/data/query"}, + {"https://example.test/api", "https://example.test/api/rum/data/query"}, + {"https://example.test/api/", "https://example.test/api/rum/data/query"}, + {"https://example.test/a/b", "https://example.test/a/b/rum/data/query"}, + {"http://192.0.2.10:12345", "http://192.0.2.10:12345/rum/data/query"}, + {"http://192.0.2.10:12345/api", "http://192.0.2.10:12345/api/rum/data/query"}, + } { + c, err := NewClient("KEY", WithBaseURL(tc.base)) + if err != nil { + t.Fatalf("NewClient(%q): %v", tc.base, err) + } + req, err := c.newRequest(t.Context(), http.MethodPost, "/rum/data/query", nil) + if err != nil { + t.Fatalf("newRequest with base %q: %v", tc.base, err) + } + req.URL.RawQuery = "" + if got := req.URL.String(); got != tc.want { + t.Errorf("base %q: request URL = %q, want %q", tc.base, got, tc.want) + } + } +} + func TestWithHTTPClientNilIgnored(t *testing.T) { c, err := NewClient("KEY", WithHTTPClient(nil)) if err != nil || c.client == nil {