ajsonrpc

raw JSON →
1.2.0 verified Sat Apr 25 auth: no python

ajsonrpc is an active, lightweight Python library (version 1.2.0) that provides an asynchronous implementation of the JSON-RPC 2.0 protocol and server capabilities, powered by asyncio. It functions as a successor to the `json-rpc` library, offering largely compatible code. It focuses on being vanilla Python with no external dependencies for its core functionality and has a release cadence driven by feature additions like new backend support.

pip install ajsonrpc
error ModuleNotFoundError: No module named 'ajsonrpc'
cause The 'ajsonrpc' library is not installed in the Python environment.
fix
Install the 'ajsonrpc' library using pip: 'pip install ajsonrpc'.
error ImportError: cannot import name 'JSONRPCResponse' from 'ajsonrpc'
cause The 'JSONRPCResponse' class has been moved to the 'core' module in 'ajsonrpc'.
fix
Update the import statement to: 'from ajsonrpc.core import JSONRPCResponse'.
error TypeError: 'coroutine' object is not callable
cause An asynchronous function was called without using 'await'.
fix
Ensure that asynchronous functions are awaited: 'response = await manager.handle(request)'.
error AttributeError: 'JSONRPCResponse' object has no attribute 'result'
cause Accessing the 'result' attribute directly on a 'JSONRPCResponse' object, which may not exist if an error occurred.
fix
Check if the 'error' attribute is present before accessing 'result': 'if response.error: handle_error(response.error) else: result = response.result'.
error RuntimeError: Event loop is closed
cause Attempting to run an asyncio event loop that has already been closed.
fix
Ensure that the event loop is open and running before executing asynchronous code: 'asyncio.run(main())'.
breaking Major interface changes occurred between pre-1.0.0 versions (0.x.x) and the stable 1.0.0 release. The 0.1.0 release was explicitly marked with an 'unstable interface,' and 1.0.0a was a 'Freezing interface' release. Users upgrading from older 0.x.x versions should review their code, especially around protocol handling and manager initialization, as direct compatibility is not guaranteed.
fix Refer to the GitHub repository's `ajsonrpc` and `json-rpc` documentation and examples for updated patterns, particularly regarding the `Dispatcher` and `JSONRPCResponseManager` usage.
gotcha By default, `JSONRPCResponseManager` returns a generic `ServerError` without detailed exception information for security reasons. If your application relies on verbose error reporting (e.g., for debugging in non-production environments), you must explicitly configure the manager to include exception details.
fix When initializing `JSONRPCResponseManager`, set `verbose_exceptions=True` (e.g., `manager = JSONRPCResponseManager(dispatcher, verbose_exceptions=True)`).
gotcha While `ajsonrpc` is designed for asynchronous operations, its core components like `JSONRPCResponseManager` can be misused in synchronous contexts. All methods intended for handling incoming RPC payloads (e.g., `get_payload_for_payload`) are `async` functions and must be `await`ed. Attempting to call them synchronously will lead to runtime errors or unexpected behavior.
fix Always use `await` when calling asynchronous methods of `ajsonrpc` components, ensuring your server loop and request handling are fully `async` compatible.
runtime status import time mem disk
3.10-alpine
3.10-slim
3.11-alpine
3.11-slim
3.12-alpine
3.12-slim
3.13-alpine
3.13-slim
3.9-alpine
3.9-slim

This quickstart demonstrates how to set up a basic `ajsonrpc` server using `asyncio.start_server`. It defines a `Dispatcher` to register RPC methods (both synchronous and asynchronous) and uses a `JSONRPCResponseManager` to handle incoming requests and generate responses. A custom `JSONRPCServerProtocol` bridges the `asyncio` transport with the `ajsonrpc` manager.

import asyncio
from ajsonrpc.manager import JSONRPCResponseManager
from ajsonrpc.dispatcher import Dispatcher
from ajsonrpc.protocol import JSONRPCServerProtocol

class MyJSONRPCServerProtocol(JSONRPCServerProtocol):
    def __init__(self, manager):
        super().__init__()
        self._manager = manager

    async def handle_request(self, payload):
        # The manager handles parsing, dispatching to methods, and error handling
        return await self._manager.get_payload_for_payload(payload)

def get_dispatcher():
    dispatcher = Dispatcher()

    @dispatcher.add_method
    def add(a, b):
        """Adds two numbers."""
        return a + b

    @dispatcher.add_method
    async def say_hello(name="World"):
        """Asynchronously greets a given name."""
        await asyncio.sleep(0.1) # Simulate async work
        return f"Hello, {name}!"

    return dispatcher

async def main():
    dispatcher = get_dispatcher()
    manager = JSONRPCResponseManager(dispatcher)

    # Create a server factory that passes the manager instance
    server_factory = lambda: MyJSONRPCServerProtocol(manager)
    
    # Start an asyncio TCP server
    server = await asyncio.start_server(server_factory, '127.0.0.1', 8080)

    addr = server.sockets[0].getsockname()
    print(f"Serving JSON-RPC on {addr}. Press Ctrl+C to stop.")

    async with server:
        await server.serve_forever()

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\nServer stopped.")

# Example usage (run this in another terminal while the server is running):
# curl -X POST -H "Content-Type: application/json" \
#      -d '{"jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": 1}' \
#      http://127.0.0.1:8080/
#
# curl -X POST -H "Content-Type: application/json" \
#      -d '{"jsonrpc": "2.0", "method": "say_hello", "params": {"name": "Async User"}, "id": 2}' \
#      http://127.0.0.1:8080/
#
# curl -X POST -H "Content-Type: application/json" \
#      -d '{"jsonrpc": "2.0", "method": "non_existent_method", "params": [], "id": 3}' \
#      http://127.0.0.1:8080/