Skip to content

feat(client): construct clients from FMP_API_KEY and FMP_BASE_URL for proxy routing - #418

Merged
benbenbang merged 3 commits into
mainfrom
feat/415-env-base-url
Oct 6, 2026
Merged

benbenbang merged 3 commits into
mainfrom
feat/415-env-base-url

Conversation

@benbenbang

Copy link
Copy Markdown
Member

Routing requests through a proxy that issues its own keys and forwards to FMP previously required wiring client options by hand in each language binding. This adds environment-driven client construction across the Rust crate, the Go SDK, and the Python package so callers can target a proxy such as valet with only FMP_API_KEY and FMP_BASE_URL set and no code change.

What changed:

  • Added environment-based constructors that read FMP_API_KEY as an apikey header and an optional FMP_BASE_URL override: ClientBuilder::from_env/Client::from_env in libfmp, NewClientFromEnv in the Go SDK, and FMP_BASE_URL fallback in FmpClient when base_url is omitted.
  • Introduced shared base URL readers that trim surrounding whitespace and treat empty or whitespace-only values as unset (fmp_base_url_from_env, BaseURLFromEnv/EnvBaseURL, resolve_base_url), replacing the default origin while preserving its path so the quote endpoint resolves under the proxy.
  • Preserved authentication and validation rules: a missing or blank key yields a missing-credential error, selecting a second authentication conflicts, explicit options still win over the environment, and plaintext HTTP to non-loopback hosts remains refused without the danger opt-in.
  • Added tests across all three bindings covering proxy targeting, the FMP origin fallback, option precedence, authentication conflicts, typed configuration errors without key leakage, and loopback and dangerous-HTTP rules; the Python suite now also unsets FMP_BASE_URL to avoid shell leakage.
  • Documented the proxy workflow and the FMP_BASE_URL variable in each README, package docs, and docstrings.

close #415

This change lets callers build a client from the process environment, which
simplifies routing through a proxy that issues its own keys and forwards to
FMP without any code change.

**Environment-driven client construction:**
* Added `ClientBuilder::from_env` and `Client::from_env`, which read
  `FMP_API_KEY` and `FMP_BASE_URL` to select the `apikey` header
  authentication and an optional base URL override while keeping the default
  path prefix.
* The key becomes `Authentication::FmpHeader`; a set base URL replaces the
  default origin and keeps its path, so `https://valet.bitbrew.app/fmp` sends
  the quote endpoint to `https://valet.bitbrew.app/fmp/stable/quote`.
* A missing or blank `FMP_API_KEY` yields `MissingCredential`; an invalid,
  unsafe, or insecure base URL reports its typed configuration error at build
  time, and selecting a second authentication fails with
  `ConflictingAuthentication`. `Client::builder` never reads the environment.

**Base URL environment reader:**
* Added `FMP_BASE_URL_ENV` and `fmp_base_url_from_env` in config, which trim
  surrounding whitespace and treat an empty or whitespace-only value as unset,
  factored through a shared `trimmed_non_empty` helper.

**Tests and documentation:**
* Added tests covering the proxy base URL, the default FMP origin fallback,
  the typed error cases, loopback and dangerous-http rules, conflicting
  authentication, and base URL trimming.
* Documented the proxy workflow in the README and switched the custom-router
  example to the `FMP_BASE_URL` variable.
This commit introduces an environment-based constructor so callers can
route through a proxy that issues its own keys, such as valet, without
wiring the options by hand.

**New environment-based client:**
* Added `NewClientFromEnv`, which reads `FMP_API_KEY` and sends it as the
  `apikey` header via `FMPHeader`, and `FMP_BASE_URL`, which replaces
  `DefaultBaseURL` while keeping its path so the quote endpoint resolves to
  the proxy origin (for example `https://valet.bitbrew.app/fmp/stable/quote`).
* Added `BaseURLFromEnv`, which reads and trims `FMP_BASE_URL` and reports
  false when unset, empty, or whitespace-only, leaving validation to
  `NewClient`.
* Exported the `EnvBaseURL` constant for the `FMP_BASE_URL` variable.
* Applied options after the environment so `WithBaseURL` wins, while
  `WithAuthentication` conflicts with the environment key; a missing or blank
  key returns `ConfigurationKindMissingCredential`, and every `NewClient`
  rule still applies, including the refusal of plaintext HTTP to a
  non-loopback host without the danger opt-in.

**Testing:**
* Added tests covering base URL normalization, proxy targeting with the
  header auth, the fallback to the FMP origin, option precedence and the
  authentication conflict, typed configuration errors with no key leakage,
  and the loopback and dangerous-HTTP rules.

**Documentation:**
* Documented the new constructor and `FMP_BASE_URL` in the README and
  package docs, noting the environment names match the Rust crate.
This commit lets `FmpClient` resolve its base URL from the `FMP_BASE_URL`
environment variable when no explicit `base_url` is passed, so a proxy
such as valet works with only `FMP_API_KEY` and `FMP_BASE_URL` set and no
code change.

**Functional change:**
* Added `resolve_base_url` in client.rs, which prefers an explicit
  `base_url` and otherwise falls back to `fmp_base_url_from_env`; a blank
  variable keeps the default `https://financialmodelingprep.com` origin.
* The variable only replaces the base URL and never selects or relaxes
  authentication, so the `token` and `FMP_API_KEY` precedence rules are
  unchanged.

**Tests:**
* Added tests/test_base_url_env.py to cover the new pickup and precedence.
* The autouse `isolated_api_key_env` fixture now also unsets `FMP_BASE_URL`
  so the developer's shell cannot leak into the suite.

**Docs:**
* Documented the behaviour in README.md with a "Using a proxy" section and
  a precedence table, and in the `__init__.pyi` and client.rs docstrings.

close #415
@benbenbang
benbenbang enabled auto-merge (rebase) October 6, 2026 09:58
@github-actions github-actions Bot added documentation Improvements or additions to documentation enhancement New feature or request labels Oct 6, 2026
@benbenbang
benbenbang merged commit c08f808 into main Oct 6, 2026
10 checks passed
@benbenbang
benbenbang deleted the feat/415-env-base-url branch October 6, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Load base URL and API key from env (FMP_BASE_URL) for proxy use

1 participant