mmar-pyhr
Pydantic-HTTP-RPC - A lightweight RPC framework based on HTTP + FastAPI with Pydantic validation.
Overview
mmar-pyhr provides a simple RPC-style interface for service-to-service communication over HTTP, similar to mmar-ptag but using HTTP instead of gRPC. It was created to address Kubernetes compatibility issues with gRPC while maintaining the same developer-friendly interface.
Features
- Type-safe RPC using Pydantic for validation
- HTTP/JSON transport (Kubernetes-friendly, no service mesh required)
- Interface-based design using Python classes
- Built-in tracing with
trace_idsupport via HTTP headers - Health check endpoints for Kubernetes pod lifecycle management
- Smart address handling (port numbers, localhost, full URLs)
- Sync/async support for service methods
Installation
uv pip install mmar-pyhr
Quick Start
Server
from mmar_pyhr import PyhrServerConfig, deploy_pyhr_server
class UserService:
def get_user(self, *, user_id: int, trace_id: str = "") -> dict:
return {"id": user_id, "name": "John Doe"}
def create_user(self, *, name: str, email: str, trace_id: str = "") -> dict:
return {"id": 123, "name": name, "email": email}
if __name__ == "__main__":
config = PyhrServerConfig(port=8000, host="0.0.0.0")
deploy_pyhr_server(
config_server=config,
service=UserService()
)
Client
from mmar_pyhr import pyhr_client
class UserServiceI:
def get_user(self, *, user_id: int, trace_id: str = "") -> dict:
raise NotImplementedError
def create_user(self, *, name: str, email: str, trace_id: str = "") -> dict:
raise NotImplementedError
# Create client
client = pyhr_client(UserServiceI, "localhost:8000")
# Make requests
user = client.get_user(user_id=42)
new_user = client.create_user(name="Alice", email="alice@example.com")
# With trace_id
user = client.get_user(user_id=42, trace_id="req-123")
Address Formats
The client accepts various address formats:
pyhr_client(Service, 9494) # → http://localhost:9494
pyhr_client(Service, ":9494") # → http://localhost:9494
pyhr_client(Service, "localhost:9494") # → http://localhost:9494
pyhr_client(Service, "http://localhost:9494") # → http://localhost:9494
pyhr_client(Service, "https://api.example.com") # → https://api.example.com
API Routes
The server automatically creates the following routes:
RPC Endpoints
POST /api/{method_name} → service.method_name(**kwargs)
Health Checks
GET /health_check → {"status": "ok"}
GET /health/liveness → {"status": "alive"}
GET /health/readiness → {"status": "ready"}
Tracing
Trace IDs are automatically propagated via the X-Trace-ID HTTP header:
# Client
client.get_user(user_id=42, trace_id="req-123")
# Server automatically receives trace_id in context
# and can use it for logging
Transport Abstraction
mmar-pyhr integrates with the mmar-mimpl transport registry:
from mmar_mimpl import get_transport
# Uses MMAR_TRANSPORT environment variable
transport = get_transport() # "pyhr" or "mmar_pyhr"
# Create client
client = transport.make_client(UserServiceI, address="localhost:8000")
# Deploy server
transport.deploy_server(
service=UserService(),
config=None,
config_server=PyhrServerConfig(port=8000)
)
Set the transport via environment variable:
export MMAR_TRANSPORT=pyhr
# or
export MMAR_TRANSPORT=mmar_pyhr
Configuration
Client Configuration
from mmar_pyhr import PyhrTransportConfig
config = PyhrTransportConfig(
timeout=30.0, # Request timeout in seconds
retry_attempts=3, # Number of retry attempts
)
Server Configuration
from mmar_pyhr import PyhrServerConfig
config = PyhrServerConfig(
host="0.0.0.0", # Bind host
port=8000, # Bind port
max_workers=1, # Number of worker processes
log_level="info", # Logging level
)
Comparison with mmar-ptag
| Feature | mmar-ptag (gRPC) | mmar-pyhr (HTTP) |
|---|---|---|
| Transport | gRPC/HTTP2 | HTTP/JSON |
| Serialization | JSON over Protobuf | Pure JSON |
| Kubernetes | Requires service mesh | Native support |
| Debugging | Requires grpcurl | Standard curl/httpie |
| Health checks | Custom implementation | Built-in HTTP endpoints |
| Load balancing | Connection-level (needs mesh) | Request-level (native K8s) |
Development
# Run tests
uv run pytest
# Build package
uv build
License
MIT
See Also
- mmar-ptag - gRPC-based RPC framework
- Architecture Decision: gRPC to HTTP migration
Metadata
Release files for mmar-pyhr 0.0.10
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mmar_pyhr-0.0.10.tar.gz | 9.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mmar_pyhr-0.0.10-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 21.4 kB
Release files / mmar_pyhr-0.0.10.tar.gz
| Download URL | mmar_pyhr-0.0.10.tar.gz |
|---|---|
| Size | 9.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
91e67b3ec27ed5c9a8c74190624b8fab4de69d995f4813eddbb57276fc274cd3
|
|
BLAKE2b-256 checksum How to use checksums |
3d211062a966bb589e5c3a9e42666a40d2aadbe293fef19726f1b0bc01154f4c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.5.31
|
Release files / mmar_pyhr-0.0.10-py3-none-any.whl
| Download URL | mmar_pyhr-0.0.10-py3-none-any.whl |
|---|---|
| Size | 11.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
90af5df9d62b2c71ab962d15a45f37cd617e37975e188ae9ac8d149ec833d114
|
|
BLAKE2b-256 checksum How to use checksums |
1ede616b84851169053d6d9bac5353d133c8c1529ba73f8bbc8a91ea62a17e76
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.5.31
|