Skip to content

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, and x-tenant-id are automatically injected into every outgoing request.
  • Declarative Caching: Enable and configure caching for GET requests 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:

  1. Reads the configuration for the "payment_api" client from your settings.toml.
  2. Instantiates the base provider (e.g., HttpxProvider).
  3. Creates and attaches the configured authentication strategy (e.g., BearerTokenAuth).
  4. Builds a ResilienceOrchestrator and injects the configured Retry and Circuit Breaker handlers.
  5. If caching is enabled for the client, it wraps the get method with the @cache decorator.
  6. 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., params, headers).

{}

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., params, headers).

{}

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., json, data, headers).

{}

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., json, data, headers).

{}

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., json, data, headers).

{}

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 name is not found.

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.