action0-client¶
Backend-agnostic, fully typed HTTP API clients: describe your API once — as typed operations — and run it synchronously, on asyncio, on Twisted — or on an execution model of your own — just by plugging in a different backend. Built on action0-req (the request/response representation) and action0-url (the URL representation).
The same typed operation, driven by three of the backends:
client = APIClient(RequestsBackend(), "https://api.example.com/v1")
item = client.send(GetItem(item_id=42)) # Item
client = APIClient(AsyncHttpxBackend(), "https://api.example.com/v1")
item = await client.send(GetItem(item_id=42)) # Awaitable[Item]
client = APIClient(TwistedBackend(), "https://api.example.com/v1")
deferred = client.send(GetItem(item_id=42)) # Deferred[Item]
(GetItem is an ordinary typed operation class, written once — the
guide shows its definition.)
Eight backends are included —
requests,
httpx (sync and async),
aiohttp,
urllib3 and
Twisted, each behind an optional extra, plus
stdlib-only urllib and thread-pool backends — and the list is open: a
backend is one small structural protocol, so writing your own takes two methods, and it drives the same
clients and operations.
Two companion projects build on this one:
action0-client-openapi
generates the typed operations, models and client for a whole API from
its OpenAPI schema — readable, checked-in code that depends on
action0-client alone; and
action0-github-api
is a fully typed GitHub REST API client that showcases the patterns on a
real API: typed pagination, conditional requests via a hook, a tuned
retry policy and streaming release-asset downloads.
uv add "action0-client[httpx]"
Highlights:
One
Client/APIClient, four execution models: the backend decides whethersend()returns a value, an awaitable, a TwistedDeferredor aconcurrent.futures.Future— and the type checker knows which, including the per-operation result type (Item,Awaitable[Item],Deferred[Item],Future[Item]).One structural
Backendprotocol, generic over the execution model’s wrapper type — implement two methods and anything can drive the same clients, including execution models this library has never heard of (Client.sendreturns whatever your backend’ssendreturns).Endpoints as typed dataclasses:
Operationfixes method and path per class, the field specifiers ofaction0.client.fieldsplace typed fields into query, headers, path templates or the JSON body.Instrumentation
Hooks (logging, metrics, tracing, request decoration) and uniform error translation into one exception family, in every execution model.Batteries for testing API clients without a server:
action0.client.testingships recording stub backends for all three execution models.Fully typed (checked with mypy strict, pyright and ty), Python 3.11+.
The action0 namespace is simply the one the author likes to use for
personal projects.