Changelog
View SourceAll notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.16.0] - 2026-02-18
Fixed
Race condition in RateLimiter.consume/2 -
consume/2previously used two separate GenServer calls (check_rate_limitthenconsume_token). Under concurrency, multiple processes could pass the check before any consumed, allowing over-consumption and negative token counts. Replaced with a single atomic{:check_and_consume, ...}GenServer call that checks availability and subtracts in one step. Extracted sharedrefill_bucket/3helper to reduce duplication betweencheck_rate_limitandcheck_and_consume.Documented dedup waiter ref-sharing edge case - Added comments explaining the shared reference mechanism in request deduplication and its safe timeout fallback when ETS entries are cleaned up between deduplicate and receive.
Req adapter connect_options overwrite -
maybe_add_ssl_optionsandmaybe_add_proxy_optionsnow merge into existing:connect_optionsinstead of overwriting. Previously, configuring both SSL and proxy on an HTTPS request would lose the SSL settings.Inconsistent response header format across adapters - Tesla adapter now normalizes response headers to
%{"key" => ["value"]}(list values), matching Finch and Req. TheResponse.t()type spec is updated to%{optional(String.t()) => [String.t()]}.Hardcoded
connection: closeheader removed - Finch and Req adapters no longer injectconnection: closeon every request. This was defeating HTTP connection pooling. Connection management is now left to the underlying client.URL double-slash with trailing base_url slash -
build_url("https://api.com/", "/users")now produceshttps://api.com/usersinstead ofhttps://api.com//users.Telemetry
circuit_key: "unknown"fallback removed -emit_state_change_eventnow requires a real circuit key. All call sites updated to pass the actual key.
Added
PATCH, HEAD, and OPTIONS HTTP methods - Added
HTTPower.patch/2,HTTPower.head/2, andHTTPower.options/2to the public API, with full client instance support.HTTPower.Configmodule - Standardized config resolution (request → application env → default) used by CircuitBreaker and RateLimiter, replacing inconsistent ad-hoc patterns.
Changed
Plug is now an optional dependency - Changed from
only: :testtooptional: trueso library consumers can useHTTPower.Testwithout independently adding Plug to their deps.Dedup cleanup interval increased from 1s to 5s - Reduces GenServer message processing overhead. Completed entries with a 500ms TTL sit harmlessly in memory for a few extra seconds before being cleaned up.
Updated moduledocs -
HTTPowerandHTTPower.Adaptermoduledocs now correctly describe the adapter-based architecture with Finch as the default.Mint.TransportError decoupled from core - Adapters now unwrap
Mint.TransportErrorstructs to plain atoms at the adapter boundary.HTTPower.ErrorandHTTPower.Retryno longer depend on Mint directly.CircuitBreaker catch-all
handle_info/2- Silently ignores unexpected messages instead of logging GenServer warnings.Generic deep merge for profile options -
deep_merge_optionsnow usesKeyword.keyword?/1instead of a hardcoded key list, automatically deep-merging any nested keyword list config.
0.15.2 - 2026-02-06
Added
- Retry-After HTTP date format support (RFC 7231) -
parse_retry_after/1now parses IMF-fixdate values (e.g.,Wed, 21 Oct 2015 07:28:00 GMT) in addition to integer seconds. Converts the date to seconds-until-that-time for use in retry backoff. Dates in the past are treated as missing. Previously only integer seconds were supported.
Changed
- CI matrix updated for Elixir 1.19 / OTP 28 - Added Elixir 1.19 and OTP 28 to test matrix, dropped OTP 25. Format, deps, and coverage jobs now run on latest versions.
- Credo strict compliance - Resolved all 14 credo strict issues: implicit try in adapters, reduced function nesting/complexity, sorted aliases, removed redundant with clause, replaced apply/3 with direct call, and other cleanups.
- Telemetry warning fix - Replaced anonymous function handlers with module-qualified
captures to eliminate
:telemetryperformance warnings. - Code simplification - Consolidated duplicate
error_message/1intoError.message/1, removed dead code, simplified control flow. Net -159 lines.
0.15.1 - 2025-10-19
Changed
- Relaxed optional dependency version requirements to prevent conflicts
- Changed Finch from
~> 0.20to>= 0.19.0(optional) - Changed Req from
~> 0.4.0to>= 0.4.0(optional) - Changed Tesla from
~> 1.11to>= 1.10.0(optional) - Prevents version conflicts in consuming applications that need different HTTP client versions
- For example, apps using Req 0.5+ alongside HTTPower will no longer encounter dependency conflicts
- Consuming apps should specify their preferred HTTP client versions in their own mix.exs
- Changed Finch from
Technical Details
- Optional dependencies now use
>=instead of~>to maximize flexibility - Minimum version requirements still ensure compatibility with HTTPower's adapter code
- All 368 tests passing with current dependency versions
- This change particularly helps when multiple packages in an app have conflicting requirements for the same HTTP client
0.15.0 - 2025-10-19
Fixed
- Critical: HTTPower.Test mocking now works when HTTPower is installed from Hex
- Fixed
HTTPower.TestInterceptorto use runtime checks instead of compile-timeMix.env()check - Test interception now works regardless of how HTTPower was compiled (hex package or local path)
- Changed from
if Mix.env() == :testto runtimeCode.ensure_loaded?(HTTPower.Test) and HTTPower.Test.mock_enabled?() - Enables
HTTPower.Test.stub/1to work in consuming applications that install HTTPower from Hex - Previously, test mocking only worked when HTTPower was compiled locally in test environment
- Fixed
Technical Details
TestInterceptor.test_enabled?/0now checks ifHTTPower.Testmodule is loaded AND mock is enabled at runtime- No changes to test mode blocking logic in
HTTPower.Client- that continues to work correctly - Separation of concerns: test_mode config blocks REAL requests, TestInterceptor enables MOCKED requests
- All 368 tests passing with zero compilation warnings
0.14.0 - 2025-10-16
Fixed
- Critical: Conditional compilation for optional adapter dependencies
- Wrapped all adapter modules (Finch, Req, Tesla) with
if Code.ensure_loaded?/1 - Adapters now only compile when their dependencies are available
- Fixes compilation errors when using HTTPower with only one adapter installed
- Enables true optional dependencies - install only what you need
- Standard Elixir pattern used by Phoenix, Ecto, and other ecosystem libraries
- Wrapped all adapter modules (Finch, Req, Tesla) with
Technical Details
- Adapter modules check dependency availability at compile time via
Code.ensure_loaded?/1 - When dependency is missing, adapter module is not defined (compilation skipped entirely)
- Runtime adapter detection (
detect_adapter/0) already usesCode.ensure_loaded?/1- no changes needed - All 380 tests passing (368 tests + 12 doctests)
- Verified compilation with various dependency combinations (Finch only, Req only, all three)
0.13.0 - 2025-10-13
Added
- Intelligent middleware coordination - Middleware now coordinate intelligently for dramatically improved system capacity
- Dedup bypasses rate limiting - Cache hits skip rate limiting entirely (5x effective capacity improvement)
- Middleware reordered: Dedup → RateLimiter → CircuitBreaker
- Pipeline short-circuits on cache hits with
{:halt, response} - Telemetry coordination metadata:
bypassed_rate_limitmeasurement +:rate_limit_bypassin metadata - Zero coupling - pure pipeline architecture
- Adaptive rate limiting - Dynamically adjusts rates based on downstream health (prevents thundering herd)
- When circuit breaker opens (service down) → 10% of normal rate
- When circuit breaker half-open (recovering) → 50% of normal rate
- When circuit breaker closed (healthy) → 100% of normal rate
- Enabled by default with
adaptive: truein rate limit config - Read-only state queries preserve loose coupling
- Telemetry events:
[:httpower, :rate_limit, :adaptive_reduction]
- Configuration profiles - Pre-configured settings for common use cases
:payment_processing- Conservative settings for payment gateways (Stripe, PayPal)- 100 req/min, 30% failure threshold, 5s dedup window
- Prevents double charges and duplicate orders automatically
:high_volume_api- High throughput for public APIs- 1000 req/min, 50% failure threshold, 1s dedup window
- Maximum throughput with dedup providing 5x capacity boost
:microservices_mesh- Balanced settings for service-to-service calls- 500 req/min, 40% failure threshold, 2s dedup window
- Prevents cascade failures and retry storms
HTTPower.Profiles.list/0- List all available profilesHTTPower.Profiles.get/1- Get profile configuration- Profiles support option overrides with deep merge (nested options preserved)
- Dedup bypasses rate limiting - Cache hits skip rate limiting entirely (5x effective capacity improvement)
Changed
Middleware pipeline handling improvements
- Fixed pipeline short-circuit bug where
{:halt, response}was incorrectly processed - Pipeline now correctly distinguishes between
{:ok, %Request{}}(continue) and{:halt, %Response{}}(short-circuit) - Removed obsolete
handle_pipeline_result/1functions (replaced with direct pattern matching) - Cleaner error handling for middleware failures
- Fixed pipeline short-circuit bug where
Profile configuration with deep merge
- User options now deep merge with profile defaults for nested keys (
:rate_limit,:circuit_breaker,:deduplicate) - Example:
profile: :high_volume_api, rate_limit: [requests: 2000]preservesper: :minutefrom profile - Prevents accidental override of entire nested config
- Explicit options always win over profile defaults
- User options now deep merge with profile defaults for nested keys (
Technical Details
- Coordination patterns
- Pattern A: Dedup bypasses rate limiting through pipeline ordering (0 lines of coupling code)
- Pattern B: Adaptive rate limiting via read-only state queries (loose coupling preserved)
- Deep merge algorithm handles nested keyword lists correctly
- Pipeline short-circuit fix
- Changed from
withstatement tocasestatement for clearer flow control - Direct pattern matching on
{:ok, %Request{}}vs{:halt, %Response{}} - Post-request handlers only called when HTTP actually executed
- Changed from
- Test improvements
- 14 new coordination tests (all passing)
- Tests use synchronous requests to avoid process dictionary issues
- Comprehensive coverage of all coordination patterns
- Performance impact
- Dedup cache hits: 5x effective capacity (skip rate limiter entirely)
- Adaptive rate limiting: Prevents thundering herd during recovery
- Zero overhead for disabled features (compile-time pipeline)
- All 371 tests passing (14 new coordination tests)
- Zero compilation warnings
- Comprehensive telemetry for observability
0.12.0 - 2025-10-13
Added
- Finch adapter - High-performance HTTP client built on Mint and NimblePool
HTTPower.Adapter.Finch- New adapter using Finch HTTP client- Performance-focused with explicit connection pooling
- Built on Mint (same low-level library that powers Req)
- SSL/TLS support with configurable verification
- Proxy support (system or custom)
- Manual JSON decoding with Jason for flexibility
- Connection pool configuration via Application config
- Comprehensive test suite (357 tests passing)
Changed
- Finch is now the default adapter (breaking change for adapter detection order)
- Adapter detection priority: Finch → Req → Tesla
- All adapters remain optional - users can choose what to install
- No breaking changes to existing code (auto-detection still works)
- Updated error message to recommend Finch first
- Updated README and documentation to reflect Finch as default
- Renamed Feature to Middleware for clearer semantics
HTTPower.Feature→HTTPower.Middleware(module namespace change)lib/httpower/feature/→lib/httpower/middleware/(directory reorganization)- All middleware modules moved:
RateLimiter,CircuitBreaker,Dedup - Updated all references in code, tests, and documentation
- Industry-standard terminology (matches Phoenix/Plug, Express, Rails)
- Zero breaking changes to public API - internal refactoring only
- Logger tests updated to use Finch adapter
- Converted from
Req.TesttoHTTPower.Test(adapter-agnostic) - All 51 logger tests now test with Finch adapter
- Tests demonstrate adapter-agnostic testing approach
- Converted from
Technical Details
- Finch adapter handles both URI structs and strings
- Header format conversion to match Req's format (map with list values)
- Automatic JSON body parsing when response is valid JSON
- Conditional supervision - Finch only started if loaded via
Code.ensure_loaded?/1 - Default pool configuration: 10 connections per pool, one pool per scheduler
- Configurable pools via
config :httpower, :finch_pools - Test coverage excludes Finch adapter (tested via integration tests)
- All production features work consistently across Finch, Req, and Tesla adapters
- Middleware pattern provides clearer mental model for request/response pipeline
- All 357 tests passing with zero compilation warnings
0.11.0 - 2025-10-13
Changed
Refactored client to extensible pipeline architecture
- Introduced
HTTPower.Featurebehaviour for composable request pipeline features - New
HTTPower.Requeststruct for context passing between pipeline stages - Generic recursive step executor works with ANY feature implementation
- Compile-time feature registry with zero overhead for disabled features
- Runtime config merging (runtime takes precedence over compile-time)
- Features can inspect, modify, short-circuit, or fail requests
- Clean separation: features communicate via
request.privatemap
- Introduced
URL validation and URI struct improvements
- Early fail-fast URL validation with clear error messages
- Parse URL once at request start, use URI struct throughout pipeline
- Direct field access:
request.url.hostinstead of helper functions - SSL check now uses pattern matching:
%URI{scheme: "https"} - Eliminates repeated URL parsing for better performance
Feature implementations refactored to use pipeline architecture
- All features (RateLimiter, CircuitBreaker, Dedup) now implement
HTTPower.Featurebehaviour - Simplified key extraction:
request.url.hostinstead of URL parsing - Features store state in
request.privatefor post-request processing - Circuit breaker and dedup can short-circuit pipeline with
{:halt, response} - More consistent error handling across all features
- All features (RateLimiter, CircuitBreaker, Dedup) now implement
Request execution flow improvements
- Request struct now built early in request lifecycle and passed throughout pipeline
- Cleaner parameter passing: 2 parameters instead of 6 in execution functions
Code cleanup and documentation
- Removed ~57 redundant comments that described what code does rather than why
- Kept important comments explaining architectural decisions
- Client.ex, RateLimiter.ex, CircuitBreaker.ex, Dedup.ex all cleaned up
- Improved code readability while maintaining comprehensive inline documentation
Technical Details
- Pipeline execution: Features run in order (RateLimiter → CircuitBreaker → Dedup)
- Zero overhead: Disabled features not included in compiled pipeline
- Post-request cleanup: Circuit breaker recording and dedup completion handled automatically
- Extensibility: Adding new features requires only implementing
HTTPower.Featurebehaviour - Type safety: URI structs ensure valid URLs throughout the pipeline
- Testability: Generic pipeline executor simplifies testing of new features
- Request flow: Request struct created early (line 103), passed through entire pipeline
- All 348 tests passing
- Zero compile warnings
- Net code addition: 434 lines (+721 -287) with significant architectural improvements
0.10.0 - 2025-10-07
Added
- Structured logging with metadata for log aggregation
- All log entries now include structured metadata via
Logger.metadata() - Request metadata:
httpower_correlation_id,httpower_event,httpower_method,httpower_url, headers, body - Response metadata:
httpower_correlation_id,httpower_event,httpower_status,httpower_duration_ms, headers, body - Exception metadata:
httpower_correlation_id,httpower_event,httpower_duration_ms,httpower_exception_kind,httpower_exception_reason - Enables powerful querying in log aggregation systems (Datadog, Splunk, ELK, Loki)
- Query examples:
httpower_duration_ms:>1000,httpower_status:>=500,httpower_correlation_id:"req_abc123" - All metadata respects
log_headersandlog_bodyconfiguration - Large bodies automatically truncated to 500 characters in metadata
- All sensitive data sanitized before adding to metadata
- Added 9 comprehensive tests for metadata functionality
- All log entries now include structured metadata via
Changed
Performance: ETS write concurrency optimization
- Added
{:write_concurrency, true}to all ETS tables (CircuitBreaker, RateLimiter, Dedup) - Expected 2-3x throughput improvement under high concurrency (50+ concurrent requests)
- Enables parallel writes across multiple processes without serialization
- Production-grade performance for high-traffic scenarios
- Added
Performance: CircuitBreaker async recording
- Switched from synchronous
GenServer.callto asyncGenServer.castfor result recording - Expected 5-10x improvement in high-throughput scenarios
- Non-blocking operation: requests don't wait for state updates
- Eventually consistent state (5-10ms delay acceptable for circuit breaker logic)
- Updated tests to handle async state changes with polling helper
- Switched from synchronous
Performance: Configuration caching optimization
- Implemented compile-time config caching using
Application.compile_env - Eliminates repeated
Application.get_envcalls on every request - Module attributes cache default config values at compile time
- Config resolution order: request-level → compile-time cached → runtime → hardcoded default
- Runtime fallback ensures tests can dynamically override config
- Particularly beneficial for high-throughput scenarios
- Implemented compile-time config caching using
Technical Details
- ETS concurrency:
{:write_concurrency, true}uses distributed locks for better parallelism - CircuitBreaker: Test updates include
await_state/3helper for polling async state changes - Config caching:
@default_adapter,@default_config,@default_failure_threshold, etc. cached at compile time - Structured logging: Machine-readable metadata fields for production observability
- All 348 tests passing (9 new tests for structured logging metadata)
- Comprehensive documentation updates across README, guides, and CLAUDE.md
0.9.0 - 2025-10-06
Added
- Comprehensive telemetry integration using Erlang's
:telemetrylibrary- HTTP request lifecycle events:
[:httpower, :request, :start],[:httpower, :request, :stop],[:httpower, :request, :exception] - Retry attempt events:
[:httpower, :retry, :attempt]with attempt_number, delay_ms, and reason - Rate limiter events:
[:httpower, :rate_limit, :ok],[:httpower, :rate_limit, :wait],[:httpower, :rate_limit, :exceeded] - Circuit breaker events:
[:httpower, :circuit_breaker, :state_change],[:httpower, :circuit_breaker, :open] - Deduplication events:
[:httpower, :dedup, :execute],[:httpower, :dedup, :wait],[:httpower, :dedup, :cache_hit] - All events include rich measurements (duration, timestamps) and metadata (method, url, status, etc.)
- URLs automatically sanitized (query params/fragments stripped) for low cardinality in metrics
- Default ports (80/443) excluded from URL telemetry for cleaner metrics
- Zero dependencies (
:telemetryships with Elixir) - Full observability guide with Prometheus, OpenTelemetry, and LiveDashboard examples
- HTTP request lifecycle events:
Integration Examples:
# Prometheus metrics
distribution("httpower.request.duration",
event_name: [:httpower, :request, :stop],
measurement: :duration,
unit: {:native, :millisecond},
tags: [:method, :status]
)
# OpenTelemetry
OpentelemetryTelemetry.register_application_tracer(:httpower)
# Custom logging
:telemetry.attach("httpower-logger", [:httpower, :request, :stop], &log_request/4, nil)Documentation:
- Added comprehensive observability guide at
guides/observability.md - Updated README with Observability & Telemetry section
- Added 11 new telemetry integration tests (339 total tests, all passing)
0.8.1 - 2025-10-01
Fixed
- Documentation updates for v0.8.0 breaking changes
- Updated all error atom references in README examples
- Updated configuration reference with new error atoms
- Updated migration guides (Tesla and Req)
- Updated production deployment guide examples
- Restructured Configuration Availability Matrix for better HTML rendering
- All documentation now correctly references
:too_many_requestsand:service_unavailable
0.8.0 - 2025-10-01
Changed
- BREAKING: Plug-compatible error atoms for Phoenix integration
- Changed
:rate_limit_exceeded→:too_many_requests(HTTP 429) - Changed
:circuit_breaker_open→:service_unavailable(HTTP 503) - Enables seamless Phoenix/Plug integration without manual error mapping
- HTTPower-specific atoms preserved:
:rate_limit_wait_timeout,:dedup_timeout, transport errors - All error handling code must be updated to use new atoms
- Changed
Migration Guide:
# Update error pattern matching:
{:error, %{reason: :rate_limit_exceeded}} # OLD
{:error, %{reason: :too_many_requests}} # NEW
{:error, %{reason: :circuit_breaker_open}} # OLD
{:error, %{reason: :service_unavailable}} # NEW0.7.1 - 2025-10-01
Fixed
- Critical: CircuitBreaker race condition in half-open state
- Fixed race condition where multiple concurrent processes could exceed
half_open_max_requestslimit - Increment counter BEFORE allowing request through (prevents concurrent bypass)
- Added comprehensive concurrent request test (10 concurrent requests, verifies only 3 allowed)
- Fixed race condition where multiple concurrent processes could exceed
- Critical: ETS table orphaning on GenServer crash
- Fixed GenServer crashes orphaning ETS tables and causing supervisor restart loops
- Added
{:heir, :none}to all ETS table creations (RateLimiter, CircuitBreaker, Dedup) - Tables now automatically deleted when owning process terminates
- Added crash recovery tests for all three GenServers
- Critical: Dedup waiter timeout memory leak
- Fixed memory leak where dead/timeout waiter processes remained in memory indefinitely
- Added process monitoring to detect when waiters die or timeout
- Automatic cleanup removes dead waiters from in-flight request lists
- Added tests for waiter death and timeout scenarios
Changed
- Performance: RateLimiter config caching
- Cache default configuration at GenServer startup (eliminates repeated
Application.get_envcalls) - ~15-20% reduction in rate limiter overhead per request
- Config changes now require GenServer restart to take effect (production-realistic behavior)
- Helper functions split into public (backward compatible) and optimized (GenServer) versions
- Cache default configuration at GenServer startup (eliminates repeated
Technical Details
- All fixes based on comprehensive architectural review (see
doc/architecture-improvements.md) - CircuitBreaker: Inverted condition and atomic increment prevents race
- ETS tables:
{:heir, :none}ensures clean supervisor restarts - Dedup: Process monitors with
:DOWNmessage handling for cleanup - RateLimiter: Cached config in GenServer state, passed to callbacks
- All 328 tests passing with comprehensive coverage of new scenarios
0.7.0 - 2025-10-01
Added
- Request deduplication - Prevent duplicate operations from double-clicks and race conditions
HTTPower.DedupGenServer for tracking in-flight requests- Hash-based fingerprinting using method + URL + body
- Response sharing: duplicate requests wait for first request to complete
- Automatic cleanup of completed requests after 500ms TTL
- Global configuration:
config :httpower, :deduplication, enabled: true - Per-request control:
deduplicate: trueordeduplicate: [key: custom_key] - Custom deduplication keys for fine-grained control
- Client-side protection that complements server-side idempotency keys
- Integrated into request pipeline (after rate limit check, before circuit breaker)
- 18 comprehensive tests covering hash generation, in-flight tracking, response sharing, cleanup, and high concurrency
- Rate limit headers parsing - Automatic detection and parsing of server rate limits from HTTP response headers
HTTPower.RateLimitHeaders.parse/2- Parses rate limit headers from responses- Supports multiple common formats:
- GitHub/Twitter style:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset - RFC 6585/IETF style:
RateLimit-Limit,RateLimit-Remaining,RateLimit-Reset - Stripe style:
X-Stripe-RateLimit-*headers Retry-Afterheader (integer seconds format)
- GitHub/Twitter style:
- Auto-detection with
:autoformat (default), or explicit format specification - Case-insensitive header matching
- Handles header values as strings, lists, or integers (adapter-agnostic)
- Rate limiter integration with server headers - Synchronize local rate limiter with server state
HTTPower.RateLimiter.update_from_headers/2- Updates bucket state from parsed headersHTTPower.RateLimiter.get_info/1- Returns current bucket information- Server-provided limits synchronize with token bucket algorithm
- Buckets continue to refill after synchronization
Technical Details
- Header parser uses format auto-detection, trying GitHub → RFC → Stripe formats in order
- Parser handles all adapter header formats (Req's list of tuples, Tesla's various formats)
- Integration updates token bucket state to match server's remaining count
- Comprehensive test coverage: 38 tests for parser, 7 tests for integration, 5 tests for Retry-After
- HTTP date format in
Retry-Aftersupported since v0.15.2 (previously only integer seconds) - Automatic backoff - Retry logic respects
Retry-Afterheader on 429/503 responses- When server provides
Retry-Afterheader (integer seconds), HTTPower uses that exact wait time - Falls back to exponential backoff when header is missing
- Only applies to 429 (Too Many Requests) and 503 (Service Unavailable) status codes
- Other retryable status codes (408, 500, 502, 504) continue using exponential backoff
- When server provides
Changed
- Code organization and readability improvements in
HTTPower.Client- Reorganized file into logical sections: Public API, Main Pipeline, Retry Logic, Adapters, Test Mode, Rate Limit Config, Circuit Breaker Config, Logging, Error Handling
- Refactored request flow to use clean
withpipelines instead of nested case statements - All helper functions now return explicit
{:ok, value}or{:error, reason}tuples for consistency - Moved test mode check to beginning of request pipeline for fail-fast behavior
- Removed redundant code comments (kept only user-facing messages and section headers)
- Simplified parameter passing by extracting options at point of use
- Eliminated unnecessary wrapper functions for cleaner call stack
- Net reduction of 27 lines while improving code clarity
Technical Details
- No performance changes - refactoring only improves maintainability
- Rate limiter and circuit breaker already have early-exit optimizations when disabled
- All 304 tests passing, 0 compile warnings
- Renamed
do_http_request/3→execute_http_request/3for clarity - Removed
do_request/3wrapper that just delegated toexecute_http_request/3
0.6.0 - 2025-09-30
Added
- Global adapter configuration - Configure HTTP adapter application-wide
config :httpower, adapter: HTTPower.Adapter.Reqfor global adapter selectionconfig :httpower, adapter: {HTTPower.Adapter.Tesla, tesla_client}for pre-configured clients- Configuration priority: per-request > per-client > global
- Allows adapter switching without code changes
- Comprehensive documentation structure in
guides/directoryguides/migrating-from-tesla.md- Complete 7-step Tesla migration guide- Emphasizes adapter-agnostic final code
- Shows HTTPower.Test for testing (not Tesla.Mock)
- Global and per-client configuration examples
guides/migrating-from-req.md- Req migration guide with error handling differencesguides/configuration-reference.md- Complete option reference with availability matrixguides/production-deployment.md- Production deployment guide with supervision tree, monitoring, security- Moved examples to
guides/examples/directory
- Configuration availability matrix showing which options work at global/per-client/per-request levels
- Updated ExDoc integration with organized guide groups (Migration Guides, Guides, Examples)
Changed
- README improvements
- Simplified "Adapter Support" section (removed confusing adapter-specific examples)
- Added "Perfect For" section at top showing target use cases
- Updated "Basic Usage" to show both direct and client-based patterns
- Split "Correlation IDs" into standalone section (not just PCI logging)
- Removed redundant "Production Considerations" and "Why HTTPower?" sections
- Updated all references from Req.Test to HTTPower.Test
- Documentation corrections across all guides
- Fixed sanitization config structure:
sanitize_headersandsanitize_body_fields(not nested undersanitize:) - Clarified that custom sanitization fields are additive (supplement defaults, not replace)
- Updated all examples to use correct configuration structure
- Fixed sanitization config structure:
Technical Details
- Global adapter configuration integrates with existing per-client/per-request options
- Adapter detection order: per-request option → global config → auto-detection (Req preferred)
- Documentation now correctly reflects implementation details
- All configuration examples consistent across README, guides, and reference docs
0.5.0 - 2025-09-30
Added
- Circuit breaker pattern implementation for protecting against cascading failures
HTTPower.CircuitBreakerGenServer with three-state machine (closed, open, half-open)- Sliding window failure tracking with unified request history
- Tracks last N requests (both successes and failures) in a single sliding window
- More accurate than separate windows for each result type
- Dual threshold strategies:
- Absolute threshold: Open circuit after N failures
- Percentage threshold: Open circuit when failure rate exceeds X%
- Automatic state transitions:
- Closed → Open: When failure threshold is exceeded
- Open → Half-Open: After timeout period expires
- Half-Open → Closed: When all test requests succeed
- Half-Open → Open: When any test request fails
- Half-open state with configurable test request limit
- Manual circuit control:
HTTPower.CircuitBreaker.open_circuit/1- Manually open a circuitHTTPower.CircuitBreaker.close_circuit/1- Manually close a circuitHTTPower.CircuitBreaker.reset_circuit/1- Reset circuit to initial stateHTTPower.CircuitBreaker.get_state/1- Check current circuit state
- Flexible circuit breaker configuration:
- Global configuration via
config :httpower, :circuit_breaker - Per-client configuration via
HTTPower.new/1 - Per-request configuration via request options
- Custom circuit keys for grouping requests
- Global configuration via
- Integration with existing retry logic: Circuit breaker complements exponential backoff
- Retry logic handles transient failures (timeouts, temporary errors)
- Circuit breaker handles persistent failures (service outages, deployment issues)
- Comprehensive test suite (26 new tests covering all states, thresholds, transitions)
- Added circuit breaker section to README with examples and best practices
Changed
- Refactored circuit breaker sliding window implementation
- Changed from separate success/failure windows to unified request tracking
Uses tuples
{:success | :failure, timestamp}for better accuracy- Window size now correctly limits total requests tracked (not per-type)
- Updated
HTTPower.Clientto integrate circuit breaker into request flow - Circuit breaker wraps retry logic to provide fail-fast behavior when circuit is open
- Updated documentation to clarify relationship between circuit breaker and retry logic
Technical Details
- Circuit breaker uses ETS for thread-safe state storage
- State transitions are logged for observability
- Circuit keys default to URL host but can be customized
- Sliding window implementation ensures accurate failure rate tracking
- Half-open state prevents thundering herd by limiting concurrent test requests
0.4.0 - 2025-09-30
Added
- Built-in rate limiting with token bucket algorithm
HTTPower.RateLimiterGenServer for managing rate limit stateHTTPower.Applicationsupervision tree for fault tolerance- Two rate limiting strategies:
:wait- Blocks until tokens are available (up tomax_wait_time):error- Returns{:error, :too_many_requests}immediately
- Flexible rate limit configuration:
- Global configuration via
config :httpower, :rate_limit - Per-client configuration via
HTTPower.new/1 - Per-request configuration via request options
- Custom bucket keys for grouping requests
- Global configuration via
- ETS-based storage for high performance and low latency
- Automatic bucket cleanup removes inactive buckets after 5 minutes
- Time window support:
:second,:minute,:hour - Thread-safe rate limiting with atomic ETS operations
- Comprehensive test suite (23 new tests covering token bucket algorithm, strategies, concurrent access)
Changed
- Updated
HTTPower.Clientto check rate limits before each request - Rate limiting integrated into request flow (happens before logging)
- Default bucket key uses URL host (can be overridden with
:rate_limit_key)
Fixed
- Fixed Plug.Conn undefined warnings by adding
@compile {:no_warn_undefined}directive toHTTPower.Test
Technical Details
- Token bucket algorithm: tokens refill continuously at configured rate
- Refill rate calculated as:
max_tokens / time_window_ms - Elapsed time since last refill determines available tokens
- GenServer handles concurrent access with ETS atomic operations
- Cleanup runs every 60 seconds, removes buckets inactive for 5+ minutes
- Works consistently across all adapters (Req, Tesla)
0.3.1 - 2025-09-30
Added
- PCI-compliant HTTP request/response logging with automatic data sanitization
HTTPower.Loggermodule for production-ready logging with security built-in- Correlation IDs for distributed tracing - every request gets a unique ID (format:
req_abc123...) - Request duration tracking - logs include timing information in milliseconds
- Automatic sanitization of sensitive data in logs:
- Credit card numbers (13-19 digits with optional spaces/dashes)
- CVV codes (3-4 digits)
- Authorization headers (Bearer tokens, Basic auth)
- API keys and secret tokens
- Password fields in JSON bodies
- Configurable custom fields via application config
- Configurable logging via application config:
enabled- Enable/disable logging globally (default: true)level- Log level: :debug, :info, :warning, :error (default: :info)sanitize_headers- Additional headers to sanitizesanitize_body_fields- Additional body fields to sanitize
- Comprehensive test suite for logging (42 new tests, 98.67% module coverage)
- Logging works consistently across all adapters (Req, Tesla)
Changed
- Updated
HTTPower.Clientto integrate logging at request/response boundaries - Request flow now includes: correlation ID generation → request logging → execution → response/error logging
- All HTTP operations now automatically log with sanitization (can be disabled via config)
Technical Details
- Correlation IDs generated using cryptographically secure random bytes
- Sanitization uses regex patterns for credit cards, CVV codes
- JSON field sanitization supports nested maps and arrays
- Headers normalized to lowercase for consistent sanitization
- Large response bodies (>500 chars) are truncated in logs
- Logging sits above adapter layer - works identically with Req or Tesla
0.3.0 - 2025-09-30
Added
- Adapter pattern supporting multiple HTTP clients (Req and Tesla)
HTTPower.Adapterbehavior for implementing custom adaptersHTTPower.Adapter.Req- adapter using Req HTTP clientHTTPower.Adapter.Tesla- adapter for existing Tesla usersHTTPower.Test- adapter-agnostic testing module with zero external dependenciesHTTPower.Test.setup/0- enables mocking for current testHTTPower.Test.stub/1- registers stub function to handle requestsHTTPower.Test.json/2,html/2,text/2- response helpersHTTPower.Test.transport_error/2- simulates network failures (timeout, connection errors, etc.)
HTTPower.TestInterceptor- clean separation of test logic from production code using compile-time checks- Comprehensive test suite proving adapter independence (50 tests total)
adapteroption for specifying which adapter to use- Smart adapter detection - automatically uses available adapter (Req preferred if both present)
- Both Req and Tesla are now optional dependencies - choose the one you need
- Example files moved to
docs/directory
Fixed
- Critical: Fixed double retry bug where Req's built-in retry ran alongside HTTPower's retry
- Critical: Fixed double error wrapping where
HTTPower.Errorstructs were wrapped multiple times - Req adapter now explicitly sets
retry: falseto disable Req's retry mechanism - Retry logic now runs consistently once per request attempt
- Error handling now checks if errors are already wrapped before wrapping again
Changed
- Internal architecture refactored to use adapter pattern (public API unchanged)
HTTPower.Clientnow routes requests through adapters instead of calling Req directly- Design principle updated from "Req-Based" to "Adapter-Based"
- Documentation updated to emphasize adapter flexibility and production features
- Refactored control flow to eliminate nested conditionals (removed
ifinsidewith,caseinsideif) - Main test suite now uses
HTTPower.Testinstead ofReq.Testfor true adapter independence
Technical Details
- Adapter abstraction allows production features (retry, circuit breaker, rate limiting) to work consistently across HTTP clients
- Symmetric dependencies: Both Req and Tesla are optional - install only what you need
- Smart adapter detection automatically selects available adapter (prefers Req if both present)
- Backward compatible: existing code continues to work (Req auto-detected if installed)
- Tesla users can now adopt HTTPower without pulling in Req dependency
- Clear error message if neither adapter is installed
- Test-mode blocking works seamlessly across both adapters
- All 50 tests passing (29 main + 9 Req adapter + 9 Tesla adapter + 3 transport error tests)
0.2.0 - 2025-01-09
Added
- Client configuration with
HTTPower.new/1for reusable HTTP clients - Base URL support for configured clients with automatic path resolution
- Option merging between client defaults and per-request settings
- Support for all HTTP methods (GET, POST, PUT, DELETE) with client instances
- Comprehensive test coverage for client configuration functionality
- HTTP status code retry logic following industry standards (408, 429, 500, 502, 503, 504)
- Exponential backoff with jitter for intelligent retry timing
- Configurable retry parameters:
base_delay,max_delay,jitter_factor - Fast unit tests for retry decision logic separated from execution
Improved
- Retry test suite performance improved by 70% (48s → 15s) through separation of concerns
- Refactored retry decision functions for better testability and maintainability
Fixed
- Corrected changelog to accurately reflect implemented vs planned features
- Updated documentation to clarify current capabilities
0.1.0 - 2025-09-09
Added
- Basic HTTP methods (GET, POST, PUT, DELETE) with clean API
- Test mode request blocking to prevent real HTTP requests during testing
- Req.Test integration for controlled HTTP testing and mocking
- Smart retry logic with configurable policies and error categorization
- Clean error handling that never raises exceptions
- SSL certificate verification with configurable options
- Proxy configuration support (system proxy and custom proxy settings)
- Request timeout management with sensible defaults
- Comprehensive error messages for common network issues
- Support for custom headers and request bodies
- Automatic Content-Type headers for POST requests
- Connection close headers for reliable request handling
- Mint.TransportError handling for detailed network error reporting
- Complete test suite with 100% coverage
- Full documentation with examples and API reference
- Hex package configuration for easy installation
Technical Details
- Built on top of Req HTTP client for reliability
- Uses Mint for low-level HTTP transport (via Req)
- Supports HTTP/1.1 and HTTP/2 protocols
- Elixir 1.14+ compatibility
- Production-ready error handling and logging
- PCI DSS compliance considerations in design