JSON-RPC clients
PyZNN provides HTTP and WebSocket JSON-RPC 2.0 transports. Both correlate integer request IDs, validate the protocol envelope, normalize transport failures, and raise structured node errors.
HTTP
Use HttpClient for request/response calls when subscriptions are not needed.
Its blocking standard-library HTTP work is moved off the event loop.
from znn.api.ledger import LedgerApi
from znn.client.http import HttpClient
client = HttpClient("https://your-node.example:35997", timeout=15)
ledger = LedgerApi(client)
momentum = await ledger.get_frontier_momentum()
print(momentum.height)
await client.disconnect()
Persistent WebSocket
WsClient keeps one socket open, supports concurrent correlated requests, and
runs a listener task for responses and subscription notifications.
from znn.api.stats import StatsApi
from znn.client.websocket import WsClient
client = WsClient(
"wss://your-node.example:35998",
reconnect=True,
reconnect_interval=1,
maximum_attempts=10,
connect_timeout=15,
)
await client.connect()
try:
sync = await StatsApi(client).sync_info()
print(sync.state)
finally:
await client.disconnect()
maximum_attempts=0 means unlimited reconnect attempts. During recovery, all
active subscriptions are restored as one set. Pending requests fail explicitly
instead of hanging, and permanent recovery failure is delivered to subscription
consumers as TransportError.
Raw requests
Most applications should use an API facade because it applies canonical method names, positional parameters, and typed result parsing. Raw calls remain available when necessary:
result = await client.send_request("ledger.getFrontierMomentum", [])
Subscriptions
Subscriptions require WebSocket and return an async iterator. Each iteration produces one normalized update object rather than the outer JSON-RPC notification envelope.
from znn.api.subscribe import SubscribeApi
subscription = await SubscribeApi(client).to_all_account_blocks()
async for account_block in subscription:
print(account_block["hash"])
Available convenience subscriptions are:
to_momentums();to_all_account_blocks();to_account_blocks_by_address(address);to_unreceived_account_blocks_by_address(address).
subscribe_to(topic, address=None) is also available, but only the canonical
topic and arity combinations are accepted.
Errors
from znn.client.errors import JsonRpcError, TransportError
try:
await LedgerApi(client).get_momentum_by_hash("0" * 64)
except JsonRpcError as error:
print(error.code, error.message, error.data)
except TransportError as error:
print(f"connection or protocol failure: {error}")
JsonRpcError preserves the node's code, message, optional data, method, and
parameters. TransportError covers connection failures, invalid JSON,
malformed JSON-RPC envelopes, response-ID mismatches, send failures, and
exhausted WebSocket recovery.
No implicit endpoint
get_default_client() remains as a compatibility helper, but its client is
intentionally unconfigured. Calling it without first configuring a trusted URL
raises TransportError; new code should construct WsClient(url) directly.
No public node is selected for you.
For complete runnable connection, concurrency, subscription, fake-transport, and error-handling examples, continue to the example cookbook.