HTTPower ⚡

HTTPower is a production-ready HTTP client library for Elixir that provides bulletproof HTTP behavior with advanced features like test mode blocking, smart retries, and comprehensive error handling.

CICoverageHex.pmDocumentation

Features

🛡️ Production-Ready Reliability

🔧 Developer-Friendly

🚀 Coming Soon (Phase 1)

Adapter Support

HTTPower works with multiple HTTP clients through its adapter system, allowing you to choose the right foundation for your needs:

Req Adapter (Default - Batteries Included)

Perfect for new projects and simple use cases. Req provides automatic JSON handling, compression, and a friendly API.

# Works out of the box - no configuration needed
HTTPower.get("https://api.example.com/users")

Tesla Adapter (Bring Your Own Configuration)

Ideal for existing applications or when you need specific HTTP client features. Use your existing Tesla setup and add HTTPower's production features on top.

# Use your existing Tesla client
tesla_client = MyApp.ApiClient.client()
client = HTTPower.new(
adapter: {HTTPower.Adapter.Tesla, tesla_client}
)
HTTPower.get(client, "/users")

Why adapters? HTTPower's production features (retry logic, circuit breakers, rate limiting, PCI logging) work consistently across all adapters. Choose the HTTP client that fits your architecture, get the reliability patterns you need.

Quick Start

Installation

Add httpower and at least one HTTP client adapter to your dependencies in mix.exs:

def deps do
[
{:httpower, "~> 0.3.0"},
# Choose at least one adapter:
{:req, "~> 0.4.0"}, # Recommended for new projects
# OR
{:tesla, "~> 1.11"} # If you already use Tesla
]
end

Note: HTTPower requires either Req or Tesla. If both are present, Req is used by default (can be overridden with the adapter option).

Basic Usage

# Simple GET request
{:ok, response} = HTTPower.get("https://api.example.com/users")
IO.inspect(response.status) # 200
IO.inspect(response.body) # %{"users" => [...]}
# POST with data
{:ok, response} = HTTPower.post("https://api.example.com/users",
body: "name=John&email=john@example.com",
headers: %{"Content-Type" => "application/x-www-form-urlencoded"}
)
# With configuration options
{:ok, response} = HTTPower.get("https://api.example.com/slow-endpoint",
timeout: 30, # 30 second timeout
max_retries: 5, # Retry up to 5 times
retry_safe: true # Retry connection resets
)
# Error handling (never raises!)
case HTTPower.get("https://unreachable-api.com") do
{:ok, response} ->
IO.puts("Success: #{response.status}")
{:error, error} ->
IO.puts("Failed: #{error.message}") # "Connection refused"
end

Test Mode Integration

HTTPower can completely block real HTTP requests during testing while allowing mocked requests:

# In test_helper.exs or test configuration
Application.put_env(:httpower, :test_mode, true)
# In your tests
defmodule MyAppTest do
use ExUnit.Case
test "API integration with mocking" do
# This will work - uses Req.Test
Req.Test.stub(HTTPower, fn conn ->
Req.Test.json(conn, %{status: "success"})
end)
{:ok, response} = HTTPower.get("https://api.example.com/test",
plug: {Req.Test, HTTPower}
)
assert response.body == %{"status" => "success"}
end
test "real requests are blocked" do
# This will be blocked in test mode
{:error, error} = HTTPower.get("https://real-api.com")
assert error.reason == :network_blocked
end
end

Configuration Options

HTTPower supports extensive configuration for production use:

HTTPower.get("https://api.example.com/endpoint",
# Request configuration
timeout: 60, # Request timeout in seconds (default: 60)
max_retries: 3, # Maximum retry attempts (default: 3)
retry_safe: false, # Retry connection resets (default: false)
# Headers and body
headers: %{
"Authorization" => "Bearer token",
"User-Agent" => "MyApp/1.0"
},
body: "request data",
# SSL and proxy
ssl_verify: true, # Enable SSL verification (default: true)
proxy: :system, # Use system proxy settings
# proxy: [host: "proxy.com", port: 8080], # Custom proxy
# Additional Req options are passed through
connect_timeout: 15_000
)

Error Handling

HTTPower provides comprehensive error handling with clean result tuples:

case HTTPower.get("https://api.example.com") do
{:ok, %HTTPower.Response{status: 200, body: body}} ->
# Success case
process_data(body)
{:ok, %HTTPower.Response{status: 404}} ->
# Handle 404 - still a successful HTTP response
handle_not_found()
{:error, %HTTPower.Error{reason: :timeout}} ->
# Network timeout
handle_timeout()
{:error, %HTTPower.Error{reason: :econnrefused}} ->
# Connection refused
handle_connection_error()
{:error, %HTTPower.Error{reason: :network_blocked}} ->
# Blocked in test mode
handle_test_mode()
end

Production Considerations

HTTPower is designed for production use with:

Reliability

Testing

Observability (Coming Soon)

Why HTTPower?

HTTPower adds production reliability patterns on top of your HTTP client choice:

vs Building It Yourself

Get circuit breakers, rate limiting, PCI-compliant logging, and telemetry integration without building and maintaining them.

vs Using Raw HTTP Clients

Adapter Flexibility

Perfect for:

Development

# Install dependencies
mix deps.get
# Run tests
mix test
# Generate docs
mix docs
# Check coverage
mix test --cover

Roadmap

See ROADMAP.md for planned features including:

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for your changes
  4. Ensure all tests pass with mix test
  5. Submit a pull request

License

MIT License - see LICENSE for details.


HTTPower: Because your HTTP requests deserve to be as powerful as they are reliable.