Skip to content
Sarj Code Standards

no-async-client-in-constructor

Inject an HTTPX AsyncClient instead of constructing one in __init__.

Why

Constructor-owned clients repeat transport setup for each service instance and hide the boundary that owns pooling and asynchronous cleanup.

Fix

Create and close an appropriately scoped AsyncClient at the async composition boundary, and inject it into consumers. Keep tenant credentials, cookies, event loops and independent ownership boundaries separate; do not replace them with a global client.

Examples

Before — flagged Do not hide client allocation in a service constructor
app/service.py
import httpx
class Service:
def __init__(self):
self.client = httpx.AsyncClient()
After — preferred Inject a client owned by the async composition scope
app/service.py
from contextlib import asynccontextmanager
import httpx
class Service:
def __init__(self, client: httpx.AsyncClient):
self.client = client
@asynccontextmanager
async def service_scope(endpoint):
async with httpx.AsyncClient(base_url=endpoint) as client:
yield Service(client)