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 == 30

Custom 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, configure transport via a link. httpLink sends one operation per HTTP request; httpBatchLink combines concurrent operations into one request. See the TypeScript client for details.

Codegen Tips

  • Run pyrpc dev in the server directory to regenerate types automatically whenever you save a .py file.
  • Or use the CLI directly: pyrpc codegen http://localhost:8000 --client ../frontend (included with pyrpc-core). pyrpc codegen accepts a running server URL, a saved schema file, or a Python module.
  • By default, pyrpc codegen writes __pyrpc.ts to the client project root. Pass --client <root> to point it elsewhere.
  • Commit the generated __pyrpc.ts to your repo so frontend builds don't depend on a running Python server.

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.";
}

Next Steps

  • Server - How procedures are defined
  • Plugins - Framework‑specific integrations