Resilient HTTP Client
Overview
The HTTP module provides a factory for creating pre-configured, resilient, and observable HTTP clients for communicating with external services. Instead of creating httpx or requests clients directly in your code, you define named clients in your configuration, and Athomic assembles them with a rich set of features.
This approach centralizes the configuration of external services and ensures that all outgoing HTTP traffic from your application is handled in a consistent, resilient, and observable way.
Key Features
- Centralized Configuration: Define all your external service clients (base URL, authentication, timeouts) in one place.
- Built-in Resilience: Automatically apply Retry and Circuit Breaker policies to your HTTP calls simply by referencing them in the configuration.
- Automatic Observability: Every request made through a Athomic client is automatically instrumented with Prometheus metrics (latency, request count, error rate) and OpenTelemetry traces.
- Automatic Context Propagation: Critical context headers like
x-request-id,x-trace-id, andx-tenant-idare automatically injected into every outgoing request. - Declarative Caching: Enable and configure caching for
GETrequests directly in your settings. - Extensible Authentication: Built-in support for Bearer Token and API Key authentication.
How It Works
You don't instantiate clients directly. Instead, you use the singleton HttpClientFactory to get a pre-configured client by name.
When you request a client (e.g., HttpClientFactory.create("payment_api")), the factory performs the following steps:
- Reads the configuration for the
"payment_api"client from yoursettings.toml. - Instantiates the base provider (e.g.,
HttpxProvider). - Creates and attaches the configured authentication strategy (e.g.,
BearerTokenAuth). - Builds a
ResilienceOrchestratorand injects the configuredRetryandCircuit Breakerhandlers. - If caching is enabled for the client, it wraps the
getmethod with the@cachedecorator. - Returns a fully assembled, ready-to-use client instance (and caches it for future calls).
Usage Example
First, define your client in settings.toml (see Configuration section below). Then, get and use the client in your code:
from nala.athomic.http import HttpClientFactory
# Get the pre-configured client for the "payment_api"
payment_api_client = HttpClientFactory.create("payment_api")
async def process_payment(payment_data: dict):
try:
# This call is automatically resilient (retries, circuit breaker)
# and observable (traces, metrics).
response = await payment_api_client.post("/v1/payments", json=payment_data)
return response
except Exception as e:
# Handle specific HTTP errors if needed
print(f"Failed to process payment: {e}")
raise
Configuration
This module's power comes from its declarative configuration. You define all clients under the [http.clients] section in your settings.toml.
[default.http]
enabled = true
# Define a dictionary of named clients
[default.http.clients]
# --- Example 1: A client for an external payment API ---
[default.http.clients.payment_api]
base_url = "[https://api.paymentservice.com](https://api.paymentservice.com)"
timeout = 15.0 # seconds
# Use Bearer Token authentication
[default.http.clients.payment_api.auth]
method = "bearer"
# Token is a secret reference
token = { path = "services/payment", key = "api_token" }
# Apply resilience policies defined in the [resilience] section
retry_policy_name = "default"
circuit_breaker_policy_name = "external_services"
# --- Example 2: A client for an internal service with caching ---
[default.http.clients.user_service]
base_url = "[http://user-service.internal:8000](http://user-service.internal:8000)"
timeout = 5.0
# Use API Key authentication
[default.http.clients.user_service.auth]
method = "api_key"
header_name = "X-Internal-API-Key"
key = { path = "services/user", key = "api_key" }
# Enable and configure caching for GET requests
[default.http.clients.user_service.cache]
enabled = true
key_prefix = "user_service_cache"
# Uses a KVStore connection named "cache_redis"
[default.http.clients.user_service.cache.kv_store_connection_name]
name = "cache_redis"
# Apply a default TTL wrapper to the cache
[[default.http.clients.user_service.cache.kv_store_connection_name.wrappers]]
name = "default_ttl"
[default.http.clients.user_service.cache.kv_store_connection_name.wrappers.config]
default_ttl_seconds = 300 # 5 minutes
API Reference
nala.athomic.http.protocol.HttpClientProtocol
Bases: BaseServiceProtocol, Protocol
Defines the contract for a resilient, lifecycle-managed HTTP client.
Any class that implements this protocol can be used by the framework to
make external HTTP requests. Inheriting from BaseServiceProtocol ensures
that the client's lifecycle (e.g., connection pooling) is managed
by Athomic's central LifecycleManager.
delete(url, **kwargs)
async
Sends an HTTP DELETE request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments to be passed to the
underlying HTTP client library (e.g., |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |
Raises:
| Type | Description |
|---|---|
HTTPRequestError
|
If the server responds with a 4xx or 5xx status. |
HTTPTimeoutError
|
If the request times out. |
ServiceNotReadyError
|
If the client has not been started. |
get(url, **kwargs)
async
Sends an HTTP GET request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments to be passed to the
underlying HTTP client library (e.g., |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |
Raises:
| Type | Description |
|---|---|
HTTPRequestError
|
If the server responds with a 4xx or 5xx status. |
HTTPTimeoutError
|
If the request times out. |
ServiceNotReadyError
|
If the client has not been started. |
patch(url, **kwargs)
async
Sends an HTTP PATCH request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments to be passed to the
underlying HTTP client library (e.g., |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |
Raises:
| Type | Description |
|---|---|
HTTPRequestError
|
If the server responds with a 4xx or 5xx status. |
HTTPTimeoutError
|
If the request times out. |
ServiceNotReadyError
|
If the client has not been started. |
post(url, **kwargs)
async
Sends an HTTP POST request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments to be passed to the
underlying HTTP client library (e.g., |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |
Raises:
| Type | Description |
|---|---|
HTTPRequestError
|
If the server responds with a 4xx or 5xx status. |
HTTPTimeoutError
|
If the request times out. |
ServiceNotReadyError
|
If the client has not been started. |
put(url, **kwargs)
async
Sends an HTTP PUT request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments to be passed to the
underlying HTTP client library (e.g., |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |
Raises:
| Type | Description |
|---|---|
HTTPRequestError
|
If the server responds with a 4xx or 5xx status. |
HTTPTimeoutError
|
If the request times out. |
ServiceNotReadyError
|
If the client has not been started. |
nala.athomic.http.factory.HttpClientFactory
Factory to create configured and resilient HTTP client instances.
This factory orchestrates the creation of HttpClientProtocol instances.
It assembles a complete client by:
1. Loading the client's specific configuration by name.
2. Enforcing Mesh-mode overrides (e.g., disabling mTLS) if applicable.
3. Instantiating the correct backend provider (e.g., Httpx).
4. Creating and attaching the configured authentication strategy.
5. Building a resilience pipeline with Retry and Circuit Breaker handlers.
6. Applying a cache decorator to the get method if configured.
Created instances are cached by name to ensure a single client instance
per configuration is used throughout the application.
create(name)
classmethod
Creates or retrieves a named, fully-configured HTTP client instance.
This is the main factory method. It builds a complete client, including its provider, authentication, resilience (retry, circuit breaker), and caching layers, based on the application's configuration.
If the application is running in MESH mode, this method automatically adjusts client settings to offload security concerns (mTLS/SSL) to the infrastructure sidecar.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The unique name of the client configuration to create, as defined in the settings file. |
required |
Returns:
| Type | Description |
|---|---|
HttpClientProtocol
|
A fully initialized and resilient HTTP client instance. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the client configuration for the given |
RuntimeError
|
If the configured provider class is not found in the registry. |
nala.athomic.http.base.HTTPClientBase
Bases: BaseService, HttpClientProtocol
Abstract base class for resilient HTTP Client providers.
This class implements the Template Method pattern, providing a shared,
robust framework for making HTTP requests. It handles common concerns like
service lifecycle, resilience orchestration (via ResilienceOrchestrator),
automatic context propagation in headers, and comprehensive observability
(metrics and tracing).
Concrete subclasses must only implement the _request
method to handle the specifics of the underlying HTTP client library.
Attributes:
| Name | Type | Description |
|---|---|---|
settings |
HttpClientSettings
|
The configuration for this specific client instance. |
resilience_orchestrator |
The orchestrator that applies resilience patterns like retry and circuit breaker to the request. |
__init__(settings, service_name, resilience_orchestrator)
Initializes the HTTPClientBase.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
HttpClientSettings
|
The configuration for this specific HTTP client. |
required |
service_name
|
str
|
A unique name for the service, used for observability. |
required |
resilience_orchestrator
|
ResilienceOrchestrator
|
An orchestrator instance to apply resilience patterns to the outgoing requests. |
required |
delete(url, **kwargs)
async
Sends an HTTP DELETE request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments for the HTTP request. |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |
get(url, **kwargs)
async
Sends an HTTP GET request.
This is a convenience method that delegates to the main _execute_request
orchestrator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments for the HTTP request. |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |
patch(url, **kwargs)
async
Sends an HTTP PATCH request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments for the HTTP request. |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |
post(url, **kwargs)
async
Sends an HTTP POST request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments for the HTTP request. |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |
put(url, **kwargs)
async
Sends an HTTP PUT request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The URL path for the request, relative to the client's base URL. |
required |
**kwargs
|
Any
|
Additional keyword arguments for the HTTP request. |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed response body. |