Client
Advanced
Testing, customization, and patterns for pyRPC clients.
Advanced Client Usage
This page covers patterns that go beyond the basic client examples.
Testing with ASGITransport
You can test the Python client against the in‑memory ASGI app instead of a real server.
import httpx
import pytest
from pyrpc_core import rpc, asgi_app, RPCClient, default_router
@pytest.fixture(autouse=True)
def clear_registry():
default_router._procedures.clear()
@pytest.mark.anyio
async def test_client_async():
@rpc
def add(a: int, b: int) -> int:
return a + b
async with RPCClient("http://test") as client:
client._async_client = httpx.AsyncClient(
transport=httpx.ASGITransport(app=asgi_app),
base_url="http://test",
)
result = await client.add.aio(10, 20)
assert result == 30Custom HTTP Settings
RPCClient uses httpx.Client / httpx.AsyncClient under the hood. You can override them:
import httpx
from pyrpc_core import RPCClient
client = RPCClient("http://localhost:8000")
client._sync_client = httpx.Client(
base_url="http://localhost:8000",
timeout=10.0,
headers={"X-Request-Source": "batch-job"},
)For TypeScript, you can wrap createClient to inject custom headers or use a different fetch implementation.
Codegen Tips
- Re‑run
pyrpc codegenwhenever you add or change procedures. - By default,
pyrpc codegengenerates types in.pyrpc/types.ts. You can map this to@pyrpc/typesusing TS path aliases. - Commit the generated types to your repo so frontend builds don't depend on Python tooling.
Error Handling Patterns
- Wrap RPC calls in a small helper that normalizes
RPCError/PyRPCError. - Map error codes to user‑facing messages in one place.
import { PyRPCError } from "@pyrpc/client";
export function handleRpcError(e: unknown): string {
if (e instanceof PyRPCError) {
if (e.code === -32601) return "Method not found.";
if (e.code === -32603) return "Internal server error.";
return e.message;
}
return "Something went wrong. Please try again.";
}