Pluggable HTTP client#149
Open
up2jj wants to merge 6 commits into
Open
Conversation
Introduce a `ConfigCat.HTTPClient` behaviour with a normalized request contract (plain maps for response/error, no HTTPoison structs at the boundary). `ConfigCat.API` becomes the default adapter wrapping HTTPoison and classifying transient vs. permanent errors. Callers can swap in Finch, Req, Mint, Tesla or a test stub via the new `:http_client` start option, which the supervisor plumbs through to the config fetcher.
HTTPoison and Finch are both declared as optional deps. ConfigCat.API guards itself with Code.ensure_loaded?/1 and raises a clear error if neither HTTPoison nor a custom :http_client is configured. ConfigCat.HTTPClient.Finch is a drop-in adapter that translates the SDK's HTTPoison-shaped timeout options to Finch's request options and reads the pool name from application config.
Pattern matching on %HTTPoison.Response{} / %HTTPoison.Error{} in
ConfigCat.API and %Finch.Response{} in ConfigCat.HTTPClient.Finch
forced the compiler to resolve those structs at compile time, so the
SDK could not compile when the optional dep was absent. Match on the
underlying map shape instead — same runtime semantics, no compile-time
coupling to the optional package.
Group the two built-in adapters under one namespace so they're discoverable side-by-side in HexDocs: ConfigCat.HTTPClient.HTTPoison (default) ConfigCat.HTTPClient.Finch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Describe the purpose of your pull request
Make the HTTP transport pluggable so the SDK no longer hard-codes HTTPoison. Apps can keep the current default, opt into the new built-in Finch adapter, or supply their own client (Req, Mint, Tesla, a test stub, ...) via a small behaviour.
ConfigCat.HTTPClientbehaviour with a normalized request/response contract (plain maps — no HTTP-client structs leak across the boundary). Adapters are responsible for classifying errors as transient vs. permanent.ConfigCat.HTTPClient.HTTPoison— the default, wraps HTTPoison. Guards itself withCode.ensure_loaded?/1and raisesArgumentErrorif HTTPoison is missing and no custom client was provided. (Replaces the previous internalConfigCat.API.)ConfigCat.HTTPClient.Finch— drop-in Finch adapter. Reads the pool name fromconfig :configcat, ConfigCat.HTTPClient.Finch, name: MyApp.Finch, translates the SDK's HTTPoison-shaped timeout options into Finch request options.:httpoisonand:finchare now declaredoptional: trueinmix.exs. Consumer apps add whichever one they want — or neither, if they ship their own adapter.%{status_code: ...},%{status: ...}) instead of struct patterns, so the SDK compiles cleanly when the optional dep is absent.ConfigFetcherdrops all HTTPoison struct pattern matches and consumes the normalized map contract instead. The internal:apifield is renamed to:http_client; the supervisor plumbs a new:http_clientstart option through to the fetcher.ConfigCatmoduledoc documents the new option.Backwards compatible on the wire: the default adapter preserves today's headers, options pass-through, and transient/permanent error split.
Related issues (only if applicable)
N/A
How to test?
mix test— the full suite (436 tests) passes against the new default adapter; fetcher and data-governance tests were updated to use normalized response maps instead of%HTTPoison.Response{}and thehttp_client:option in place ofapi:.ConfigCat.HTTPClient, pass it viahttp_client:, and verifyConfigFetcherworks without HTTPoison being called. The Mox-backedConfigCat.MockAPI(now mockingConfigCat.HTTPClient) is a ready-made example.:httpoisonfrom a consumer app's deps without setting:http_client— startup raises a clearArgumentErrorinstructing the user to either add HTTPoison or provide their own client.{:finch, "~> 0.18"}, start{Finch, name: MyApp.Finch}in the supervision tree, configureconfig :configcat, ConfigCat.HTTPClient.Finch, name: MyApp.Finch, and passhttp_client: ConfigCat.HTTPClient.FinchtoConfigCat.start_link/1. Verified end-to-end against the ConfigCat CDN with a fresh consumer app that has no HTTPoison in its deps: the SDK compiled, fetched a live config, and evaluated flags successfully.{:error, %{reason: :timeout, transient?: true}}and{:error, %{reason: :unauthorized, transient?: false}}; verify the fetcher's retry/log behavior matches the previous HTTPoison-coupled implementation.Security
The SDK still only issues outbound HTTPS requests to the ConfigCat CDN. Custom adapters run in the user's own application process and inherit whatever TLS/proxy posture they configure for their HTTP client — that boundary is now explicit (a documented behaviour) rather than implicit (HTTPoison/hackney options leaked through the SDK).
Requirement checklist