A simple, flexible Python HTTP client and API modeling toolkit built on httpx and pydantic.
Project description
pyrest-model-client
A simple, flexible Python HTTP client and API modeling toolkit built on top of httpx and pydantic. Easily integrate robust API requests and resource models into your Python projects.
🚀 Features
- Model-driven: Define and interact with API resources as Python classes using
BaseAPIModel. - Easy HTTP Requests: Simple
RestApiClientfor GET, POST, PUT, DELETE with automatic header and base URL management. - Async Support: Full async/await support with
AsyncRestApiClientfor high-performance concurrent requests. - Automatic Endpoint Normalization: Configurable endpoint path normalization (trailing slash handling).
- Resource Path Integration: Models can use their
resource_pathto generate endpoints and URLs automatically. - Flexible Authentication: Support for Token and Bearer authentication via
build_header()helper. - Response to Model Conversion:
get_model_fields()helper converts API responses to typed model instances. - Configurable Client: Customizable timeout, connection pool limits, and redirect handling.
- Type Safety: All models use Pydantic for automatic validation and serialization.
- Error Handling: Automatic HTTP status error handling with
raise_for_status(). - Extensible: Easily create new models for any RESTful resource by extending
BaseAPIModel.
📦 Installation
uv add pyrest-model-client
🔧 Usage
1. Define Your Models
from pyrest_model_client.base import BaseAPIModel
class User(BaseAPIModel):
name: str
email: str
resource_path: str = "user"
class Environment(BaseAPIModel):
name: str
resource_path: str = "environment"
2. Initialize the Client and Make Requests
import os
from dotenv import load_dotenv
from pyrest_model_client import RestApiClient, build_header, get_model_fields
from pyrest_model_client.base import BaseAPIModel
load_dotenv()
TOKEN = os.getenv("TOKEN")
BASE_URL = f'{os.getenv("BASE_URL")}:{os.getenv("PORT")}'
class FirstApp(BaseAPIModel):
"""
Model representing the FirstApp API resource. The fields should match the API response structure.
The app resource path is defined as "first_app" in the API.
"""
name: str
description: str | None = None
resource_path: str = "first_app"
# Initialize the client with default settings
header = build_header(token=TOKEN)
client = RestApiClient(base_url=BASE_URL, header=header)
# Or configure the client with custom settings
import httpx
client = RestApiClient(
base_url=BASE_URL,
header=header,
timeout=httpx.Timeout(60.0, connect=10.0), # 60s read, 10s connect
add_trailing_slash=True, # Automatically add trailing slashes
limits=httpx.Limits(max_keepalive_connections=5, max_connections=10)
)
# Example: Use resource_path from model
app = FirstApp(name="My App", description="Test")
endpoint = app.get_endpoint() # Returns "first_app"
full_url = app.get_resource_url(client) # Returns full URL
# Example: Get all items from the API (paginated) and convert them to model instances
item_list = []
params = None
while res := client.get("first_app", params=params):
item_list.extend(get_model_fields(res["results"], model=FirstApp))
if not res["next"]:
break
params = {"page": res["next"].split("/?page=")[-1]}
# Example: Create a new item
new_item = client.post("first_app", data={"name": "My App", "description": "A new app"})
# Example: Update an item
updated_item = client.put("first_app/1", data={"name": "Updated App"})
# Example: Delete an item
client.delete("first_app/1")
3. Using Async Client
import os
import asyncio
from dotenv import load_dotenv
from pyrest_model_client import AsyncRestApiClient, build_header
from pyrest_model_client.base import BaseAPIModel
load_dotenv()
TOKEN = os.getenv("TOKEN")
BASE_URL = f'{os.getenv("BASE_URL")}:{os.getenv("PORT")}'
async def main():
header = build_header(token=TOKEN)
# Use async client as context manager
async with AsyncRestApiClient(base_url=BASE_URL, header=header) as client:
# Make async requests
response = await client.get("first_app")
new_item = await client.post("first_app", data={"name": "Async App"})
updated = await client.put("first_app/1", data={"name": "Updated"})
await client.delete("first_app/1")
asyncio.run(main())
🤝 Contributing
Contributions are welcome! Please fork the repo, create a branch, and submit a pull request.
📄 License
MIT License — see LICENSE for details.
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 pyrest_model_client-1.0.4.tar.gz.
File metadata
- Download URL: pyrest_model_client-1.0.4.tar.gz
- Upload date:
- Size: 9.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1da3419b986c599d0b96c47afcf1269788c0423409c8784a89d7a16b0ee1986
|
|
| MD5 |
11f6c39dfbcdad5ff3bbf73833471c19
|
|
| BLAKE2b-256 |
07edf0d0d1a64c1654286363786bf5d3e473f69b189b3cfd57e59a23ddf8f222
|
File details
Details for the file pyrest_model_client-1.0.4-py3-none-any.whl.
File metadata
- Download URL: pyrest_model_client-1.0.4-py3-none-any.whl
- Upload date:
- Size: 7.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89d97eb16603926406e9fb6a07e43fde136ce38c4550663f6b3be5343eb35ac6
|
|
| MD5 |
65dfe39e8b1ae760a96de47f48fe6ff0
|
|
| BLAKE2b-256 |
2ca014f0ed55da24c408d32e521d66c01ee5a322592aed0ecadb33d0113d3bca
|