PyAPIq is a modern Python toolkit for building both synchronous and asynchronous API clients with clean, minimal code and full type safety.
Project description
📦 PyAPIq
PyAPIq is a modern Python toolkit for building both synchronous and asynchronous API clients with clean, minimal code and full type safety.
Define endpoints using decorators like @sync_endpoint or @async_endpoint, structure logic with optional namespaces,
and leverage Pydantic models for strict request/response validation — all with built-in rate limiting and retries.
Installation
pip install pyapiq
Quickstart
1. Define your models
Use Pydantic to define request and response schemas with full type safety:
from typing import List
from pydantic import BaseModel
class BulkAccountsRequest(BaseModel):
account_ids: List[str]
class AccountInfoResponse(BaseModel):
address: str
balance: int
status: str
class BulkAccountsResponse(BaseModel):
accounts: List[AccountInfoResponse]
2. Define your client
Declare your API client by subclassing AsyncClientAPI and annotating endpoints with @async_endpoint:
from pyapiq import AsyncClientAPI, async_endpoint
from pyapiq.types import HTTPMethod
class AsyncTONAPI(AsyncClientAPI):
base_url = "https://tonapi.io"
headers = {"Authorization": "Bearer <YOUR_API_KEY>"}
version = "v2"
rps = 1
max_retries = 2
@async_endpoint(HTTPMethod.GET)
async def status(self) -> dict:
"""Check API status (GET /status)"""
@async_endpoint(HTTPMethod.GET)
async def rates(self, tokens: str, currencies: str) -> dict:
"""Get token rates (GET /rates?tokens={tokens}¤cies={currencies})"""
Notes:
- If you prefer synchronous clients, simply use
SyncClientAPIwith@sync_endpointinstead. - For synchronous clients, use
SyncClientAPIand@sync_endpoint— interface is fully symmetrical. - Method arguments are automatically mapped to path and query parameters. The return value is parsed from JSON and
returned as a
dict, unless areturn_as=Modelis specified.
3. Group endpoints with namespaces (optional)
Use AsyncAPINamespace to logically organize endpoints under a common prefix (e.g., /accounts):
from pyapiq import AsyncAPINamespace, async_endpoint
from pyapiq.types import HTTPMethod
class Accounts(AsyncAPINamespace):
namespace = "accounts"
@async_endpoint(HTTPMethod.GET, path="/{account_id}", return_as=AccountInfoResponse)
async def info(self, account_id: str) -> AccountInfoResponse:
"""Retrieve account information by account_id (GET /accounts/{account_id})"""
@async_endpoint(HTTPMethod.POST, path="/_bulk", return_as=BulkAccountsResponse)
async def bulk_info(self, payload: BulkAccountsRequest) -> BulkAccountsResponse:
"""Retrieve info for multiple accounts with a Pydantic model (POST /accounts/_bulk)"""
@async_endpoint(HTTPMethod.POST, path="/_bulk")
async def bulk_info_dict(self, payload: dict) -> dict:
"""Retrieve info for multiple accounts with a dict payload (POST /accounts/_bulk)"""
Then include the namespace in your main client:
class AsyncTONAPI(AsyncClientAPI):
base_url = "https://tonapi.io"
headers = {"Authorization": "Bearer <YOUR_API_KEY>"}
version = "v2"
rps = 1
max_retries = 2
# ... endpoints above ...
@property
def accounts(self) -> Accounts:
return Accounts(self)
Note:
The namespace can be defined with or without a leading slash. It will be joined correctly with endpoint paths. Each
namespace instance receives the parent client instance automatically.
4. Usage
async def main():
tonapi = AsyncTONAPI()
async with tonapi:
# GET /status
status = await tonapi.status()
print(status)
Note:
Always use async with to open and close the session properly. All retries, throttling, and connection reuse are
handled under the hood.
API Configuration
All settings are defined as class attributes on your client class:
| Name | Type | Description | Default |
|---|---|---|---|
base_url |
str | Base URL of the API (must start with http:// or https://) |
— |
version |
str | Optional API version prefix (e.g. "v1" → /v1/... in requests) |
None |
rps |
int | Max requests per second (client-side rate limit) | 1 |
max_retries |
int | Max automatic retries for HTTP 429 (Too Many Requests) | 3 |
headers |
dict | Default headers to send with each request | None |
cookies |
dict | Default cookies to send with each request | None |
timeout |
float | Default request timeout in seconds | None |
Note:
The version field is automatically prefixed to all endpoint paths (e.g. /v2/accounts/...).
Rate limiting and retries are handled transparently and apply only per-client instance.
Endpoints
-
Use
@async_endpoint(method, path=..., return_as=...)to declare each endpoint. -
All method arguments are automatically mapped:
- Scalars → query/path parameters
- dict or Pydantic models → request body
-
return_as=Modellets you parse responses into Pydantic models. -
If omitted, response is returned as
dict.
Note:
If path is omitted, the method name becomes the endpoint path (e.g. rates → /rates). You can define both flat and
namespaced methods together.
Notes
- Fully asynchronous: all clients and endpoints require
async with. - Zero boilerplate: request building, error handling, retries, and throttling are automatic.
- Namespaces help organize large APIs, but are optional.
- Both dicts and Pydantic models are supported in request payloads.
- Great for building typed SDKs or internal tools.
Contribution
We welcome your contributions! If you find a bug or have an idea, please open an issue or submit a pull request.
License
Distributed under the MIT License. Use freely for commercial or personal projects.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyapiq-0.2.1.tar.gz.
File metadata
- Download URL: pyapiq-0.2.1.tar.gz
- Upload date:
- Size: 16.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c210a97c6fd6e4bac5279989e68c2ac6906db193b14aca29cb39457d26814fef
|
|
| MD5 |
9caf1f486bffdded7c6ce0b0fa6417d6
|
|
| BLAKE2b-256 |
c2bac465fd5c35fc3a07de086b74a38dd3f1db254a1d9a8c5e0dabd06659b695
|
File details
Details for the file pyapiq-0.2.1-py3-none-any.whl.
File metadata
- Download URL: pyapiq-0.2.1-py3-none-any.whl
- Upload date:
- Size: 19.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36f80bd3684ba091102fe90900de9de1e8d639b7cef5808106a01cfe4baffad3
|
|
| MD5 |
15063719bd92f86e5ff256710acc3967
|
|
| BLAKE2b-256 |
c55ba2e3e37607c4f8d80accfbf4481df35bd7d73c655c2afcf407a1bdecf478
|