Python API clients, thoughtfully structured.
unihttp – modern library for creating declarative API clients
Describe an endpoint once. Call it as a typed Python method. Keep your HTTP transport and response models separate.
Sync & async clients · Explicit request parameters · Pluggable serializers
An endpoint you can read.
The URL, parameters, and result type live together in a small dataclass.
bind_method exposes it on your client with a typed call signature.
- Declare the result.
Userdescribes the response your code receives. - Describe the request.
Path[int]placesuser_idin the URL. - Bind the method.
get_user(user_id=1)returns aUserwith the configured response loader; await the call with async clients.
Choose an HTTP library in the tabs. The models stay the same; the client changes. These excerpts omit shared imports and configuration. See the complete sync or async example to run against a local demo API. aiohttp is async-only.
Endpoint & client · Python
from unihttp.clients.httpx import HTTPXSyncClient
@dataclass
class User:
id: int
name: str
@dataclass
class GetUser(BaseMethod[User]):
__url__ = "/users/{user_id}"
__method__ = "GET"
user_id: Path[int]
class UserClient(HTTPXSyncClient):
get_user = bind_method(GetUser)
from unihttp.clients.requests import RequestsSyncClient
@dataclass
class User:
id: int
name: str
@dataclass
class GetUser(BaseMethod[User]):
__url__ = "/users/{user_id}"
__method__ = "GET"
user_id: Path[int]
class UserClient(RequestsSyncClient):
get_user = bind_method(GetUser)
from unihttp.clients.aiohttp import AiohttpAsyncClient
@dataclass
class User:
id: int
name: str
@dataclass
class GetUser(BaseMethod[User]):
__url__ = "/users/{user_id}"
__method__ = "GET"
user_id: Path[int]
class UserClient(AiohttpAsyncClient):
get_user = bind_method(GetUser)
from unihttp.clients.httpx2 import HTTPX2SyncClient
@dataclass
class User:
id: int
name: str
@dataclass
class GetUser(BaseMethod[User]):
__url__ = "/users/{user_id}"
__method__ = "GET"
user_id: Path[int]
class UserClient(HTTPX2SyncClient):
get_user = bind_method(GetUser)
from unihttp.clients.niquests import NiquestsSyncClient
@dataclass
class User:
id: int
name: str
@dataclass
class GetUser(BaseMethod[User]):
__url__ = "/users/{user_id}"
__method__ = "GET"
user_id: Path[int]
class UserClient(NiquestsSyncClient):
get_user = bind_method(GetUser)
from unihttp.clients.zapros import ZaprosSyncClient
@dataclass
class User:
id: int
name: str
@dataclass
class GetUser(BaseMethod[User]):
__url__ = "/users/{user_id}"
__method__ = "GET"
user_id: Path[int]
class UserClient(ZaprosSyncClient):
get_user = bind_method(GetUser)
from unihttp.clients.urllib import UrllibSyncClient
@dataclass
class User:
id: int
name: str
@dataclass
class GetUser(BaseMethod[User]):
__url__ = "/users/{user_id}"
__method__ = "GET"
user_id: Path[int]
class UserClient(UrllibSyncClient):
get_user = bind_method(GetUser)
Your API contract. Your stack.
Method definitions describe the API, not the transport. Choose an HTTP client for your application and a serializer for your models.
Build beyond the first request.
Define your API Map query parameters, JSON bodies, headers, and files.
Go asynchronous Use async clients, context managers, and middleware.
Handle failures Choose how HTTP errors become application exceptions.
Add authentication Apply a bearer token through request middleware.
Stream a response Read downloads incrementally and close streams safely.
Look up the API Find exact signatures, types, and extension points.
When unihttp fits
Use it for a reusable API client or SDK with explicit endpoint contracts. For a one-off request, calling your HTTP library directly may be sufficient.