diff --git a/internal/config/config.go b/internal/config/config.go index c166b2a..cc7009e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -42,12 +42,6 @@ func Load() (Config, error) { return Config{}, err } apiKey := strings.TrimSpace(os.Getenv(envWherobotsAPIKey)) - if apiKey == "" { - return Config{}, fmt.Errorf( - "%s is required\n\nTo create an API key, visit: %s\nThen export it:\n\n export %s=''", - envWherobotsAPIKey, apiKeyURL(openAPIURL), envWherobotsAPIKey, - ) - } cacheRoot, err := os.UserCacheDir() if err != nil { @@ -81,6 +75,18 @@ func Load() (Config, error) { }, nil } +// RequireAPIKey returns an error with setup instructions when the API key is +// empty, or nil when a key is present. +func (c Config) RequireAPIKey() error { + if c.APIKey != "" { + return nil + } + return fmt.Errorf( + "%s is required\n\nTo create an API key, visit: %s\nThen export it:\n\n export %s=''", + envWherobotsAPIKey, apiKeyURL(c.OpenAPIURL), envWherobotsAPIKey, + ) +} + // urlCacheKey returns a short hex string derived from the URL so that // different API endpoints get separate cache files. func urlCacheKey(rawURL string) string { diff --git a/internal/config/config_test.go b/internal/config/config_test.go index c03a4ba..427ab44 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -41,32 +41,48 @@ func TestLoadBuildsSpecURLFromWherobotsAPIURL(t *testing.T) { } } -func TestLoadRequiresWherobotsAPIKey(t *testing.T) { +func TestLoadSucceedsWithoutAPIKey(t *testing.T) { t.Setenv("WHEROBOTS_API_URL", "") t.Setenv("WHEROBOTS_API_KEY", "") - _, err := Load() + cfg, err := Load() + if err != nil { + t.Fatalf("Load() error = %v", err) + } + if cfg.APIKey != "" { + t.Fatalf("APIKey = %q, want empty", cfg.APIKey) + } +} + +func TestRequireAPIKeyErrorsWithDefaultURL(t *testing.T) { + cfg := Config{OpenAPIURL: "https://api.cloud.wherobots.com/openapi.json"} + err := cfg.RequireAPIKey() if err == nil { - t.Fatalf("expected Load() error") + t.Fatalf("expected error") } if !strings.Contains(err.Error(), "https://cloud.wherobots.com/settings#api-keys") { t.Fatalf("error should contain default API key URL, got: %v", err) } } -func TestLoadMissingKeyUsesCustomAPIHost(t *testing.T) { - t.Setenv("WHEROBOTS_API_URL", "https://api.staging.wherobots.com") - t.Setenv("WHEROBOTS_API_KEY", "") - - _, err := Load() +func TestRequireAPIKeyErrorsWithCustomURL(t *testing.T) { + cfg := Config{OpenAPIURL: "https://api.staging.wherobots.com/openapi.json"} + err := cfg.RequireAPIKey() if err == nil { - t.Fatalf("expected Load() error") + t.Fatalf("expected error") } if !strings.Contains(err.Error(), "https://staging.wherobots.com/settings#api-keys") { t.Fatalf("error should contain custom API key URL, got: %v", err) } } +func TestRequireAPIKeySucceedsWithKey(t *testing.T) { + cfg := Config{APIKey: "key-1"} + if err := cfg.RequireAPIKey(); err != nil { + t.Fatalf("unexpected error: %v", err) + } +} + func TestCachePathIsKeyedOnAPIURL(t *testing.T) { t.Setenv("WHEROBOTS_API_KEY", "key-1") diff --git a/internal/executor/request.go b/internal/executor/request.go index d4c8a48..2cbd879 100644 --- a/internal/executor/request.go +++ b/internal/executor/request.go @@ -46,8 +46,8 @@ func BuildRequest( if runtimeSpec.BaseURL == "" { return nil, fmt.Errorf("missing base URL (no OpenAPI servers and WHEROBOTS_API_URL has no resolvable host)") } - if cfg.APIKey == "" { - return nil, fmt.Errorf("WHEROBOTS_API_KEY is required") + if err := cfg.RequireAPIKey(); err != nil { + return nil, err } if len(pathArgs) != len(op.PathParamOrder) { return nil, fmt.Errorf("expected %d path arguments, got %d", len(op.PathParamOrder), len(pathArgs)) diff --git a/internal/executor/request_test.go b/internal/executor/request_test.go index 894ae42..1ae864a 100644 --- a/internal/executor/request_test.go +++ b/internal/executor/request_test.go @@ -75,7 +75,7 @@ func TestBuildRequestMissingAPIKeyReturnsError(t *testing.T) { op := &spec.Operation{Method: "GET", Path: "/users"} _, err := BuildRequest(context.Background(), cfg, runtimeSpec, op, nil, nil, "") - if err == nil || !strings.Contains(err.Error(), "WHEROBOTS_API_KEY is required") { + if err == nil || !strings.Contains(err.Error(), "WHEROBOTS_API_KEY") { t.Fatalf("expected API key error, got %v", err) } }