{"id":15009420,"url":"https://github.com/pengutronix/aiohttp-json-rpc","last_synced_at":"2025-10-03T18:30:47.659Z","repository":{"id":46775667,"uuid":"46267041","full_name":"pengutronix/aiohttp-json-rpc","owner":"pengutronix","description":"Implements JSON-RPC 2.0 using aiohttp","archived":true,"fork":false,"pushed_at":"2021-09-26T17:37:02.000Z","size":238,"stargazers_count":55,"open_issues_count":10,"forks_count":18,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-01-15T00:19:23.835Z","etag":null,"topics":["aiohttp","django","http-client","http-server","json-rpc","python","python-3-5","python-3-6"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pengutronix.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-16T10:12:15.000Z","updated_at":"2024-07-23T01:37:34.000Z","dependencies_parsed_at":"2022-09-02T12:12:11.913Z","dependency_job_id":null,"html_url":"https://github.com/pengutronix/aiohttp-json-rpc","commit_stats":null,"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pengutronix%2Faiohttp-json-rpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pengutronix%2Faiohttp-json-rpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pengutronix%2Faiohttp-json-rpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pengutronix%2Faiohttp-json-rpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pengutronix","download_url":"https://codeload.github.com/pengutronix/aiohttp-json-rpc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235173147,"owners_count":18947449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aiohttp","django","http-client","http-server","json-rpc","python","python-3-5","python-3-6"],"created_at":"2024-09-24T19:25:11.076Z","updated_at":"2025-10-03T18:30:47.249Z","avatar_url":"https://github.com/pengutronix.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":".. image:: https://img.shields.io/pypi/v/aiohttp-json-rpc.svg\n   :target: https://pypi.org/project/aiohttp-json-rpc\n\n.. image:: https://img.shields.io/travis/com/pengutronix/aiohttp-json-rpc/master.svg?label=Linux%20build%20%40%20Travis%20CI\n   :target: http://travis-ci.com/pengutronix/aiohttp-json-rpc\n\n.. image:: https://img.shields.io/pypi/pyversions/aiohttp-json-rpc.svg\n\naiohttp-json-rpc\n================\n\nImplements `JSON-RPC 2.0 Specification \u003chttp://www.jsonrpc.org/specification\u003e`_ using `aiohttp \u003chttp://aiohttp.readthedocs.org/en/stable/\u003e`_\n\n+---------------+---------------+\n| Protocol      | Support       |\n+===============+===============+\n| Websocket     | since v0.1    |\n+---------------+---------------+\n| POST          | TODO          |\n+---------------+---------------+\n| GET           | TODO          |\n+---------------+---------------+\n\n\nInstallation\n------------\n\n.. code-block:: shell\n\n  pip install aiohttp-json-rpc\n\n\nUsage\n-----\n\nRPC methods can be added by using ``rpc.add_method()``.\n\nAll RPC methods are getting passed a ``aiohttp_json_rpc.communicaton.JsonRpcRequest``.\n\n\nServer\n~~~~~~\n\nThe following code implements a simple RPC server that serves the method ``ping`` on ``localhost:8080``.\n\n.. code-block:: python\n\n  from aiohttp.web import Application, run_app\n  from aiohttp_json_rpc import JsonRpc\n  import asyncio\n\n\n  async def ping(request):\n      return 'pong'\n\n\n  if __name__ == '__main__':\n      loop = asyncio.get_event_loop()\n\n      rpc = JsonRpc()\n      rpc.add_methods(\n          ('', ping),\n      )\n\n      app = Application(loop=loop)\n      app.router.add_route('*', '/', rpc.handle_request)\n\n      run_app(app, host='0.0.0.0', port=8080)\n\n\nClient (JS)\n~~~~~~~~~~~\n\nThe following code implements a simple RPC client that connects to the server above\nand prints all incoming messages to the console.\n\n.. code-block:: html\n\n  \u003cscript src=\"//code.jquery.com/jquery-2.2.1.js\"\u003e\u003c/script\u003e\n  \u003cscript\u003e\n    var ws = new WebSocket(\"ws://localhost:8080\");\n    var message_id = 0;\n\n    ws.onmessage = function(event) {\n      console.log(JSON.parse(event.data));\n    }\n\n    function ws_call_method(method, params) {\n      var request = {\n        jsonrpc: \"2.0\",\n        id: message_id,\n        method: method,\n        params: params\n      }\n\n      ws.send(JSON.stringify(request));\n      message_id++;\n    }\n  \u003c/script\u003e\n\nThese are example responses the server would give if you call ``ws_call_method``.\n\n.. code-block:: html\n\n  --\u003e ws_call_method(\"get_methods\")\n  \u003c-- {\"jsonrpc\": \"2.0\", \"result\": [\"get_methods\", \"ping\"], \"id\": 1}\n\n  --\u003e ws_call_method(\"ping\")\n  \u003c-- {\"jsonrpc\": \"2.0\", \"method\": \"ping\", \"params\": \"pong\", \"id\": 2}\n\nClient (Python)\n~~~~~~~~~~~~~~~\n\nThere's also Python client, which can be used as follows:\n\n.. code-block:: python\n\n  from aiohttp_json_rpc import JsonRpcClient\n\n\n  async def ping_json_rpc():\n      \"\"\"Connect to ws://localhost:8080/, call ping() and disconnect.\"\"\"\n      rpc_client = JsonRpcClient()\n      try:\n          await rpc_client.connect('localhost', 8080)\n          call_result = await rpc_client.call('ping')\n          print(call_result)  # prints 'pong' (if that's return val of ping)\n      finally:\n          await rpc_client.disconnect()\n\n\n  asyncio.get_event_loop().run_until_complete(ping_json_rpc())\n\nOr use asynchronous context manager interface:\n\n.. code-block:: python\n\n  from aiohttp_json_rpc import JsonRpcClientContext\n  \n  \n  async def jrpc_coro():\n      async with JsonRpcClientContext('ws://localhost:8000/rpc') as jrpc:\n          # `some_other_method` will get request.params filled with `args` and\n          # `kwargs` keys:\n          method_res = await jrpc.some_other_method('arg1', key='arg2')\n  \n      return method_res\n  \n  asyncio.get_event_loop().run_until_complete(jrpc_coro())\n\n\nFeatures\n--------\n\nError Handling\n~~~~~~~~~~~~~~\n\nAll errors specified in the `error specification \u003chttp://www.jsonrpc.org/specification#error_object\u003e`_ but the InvalidParamsError are handled internally.\n\nIf your coroutine got called with wrong params you can raise an ``aiohttp_json_rpc.RpcInvalidParamsError`` instead of sending an error by yourself.\n\nThe JSONRPC protocol defines a range for server defined errors.\n``aiohttp_json_rpc.RpcGenericServerDefinedError`` implements this feature.\n\n.. code-block:: python\n\n  from aiohttp_json_rpc import RpcInvalidParamsError\n\n\n  async def add(request):\n      try:\n          a = params.get('a')\n          b = params.get('b')\n\n          return a + b\n\n      except KeyError:\n          raise RpcInvalidParamsError\n\n\n    async def add(request):\n        raise RpcGenericServerDefinedError(\n            error_code=-32050,\n            message='Computer says no.',\n        )\n\n\nError Logging\n~~~~~~~~~~~~~\n\nEvery traceback caused by an RPC method will be caught and logged.\n\nThe RPC will send an RPC ServerError and proceed as if nothing happened.\n\n.. code-block:: python\n\n  async def divide(request):\n      return 1 / 0  # will raise a ZeroDivisionError\n\n.. code-block::\n\n  ERROR:JsonRpc: Traceback (most recent call last):\n  ERROR:JsonRpc:   File \"aiohttp_json_rpc/base.py\", line 289, in handle_websocket_request\n  ERROR:JsonRpc:     rsp = yield from methods[msg['method']](ws, msg)\n  ERROR:JsonRpc:   File \"./example.py\", line 12, in divide\n  ERROR:JsonRpc:     return 1 / 0\n  ERROR:JsonRpc: ZeroDivisionError: division by zero\n\n\nPublish Subscribe\n~~~~~~~~~~~~~~~~~\n\nAny client of an RPC object can subscribe to a topic using the built-in RPC method ``subscribe()``.\n\nTopics can be added using ``rpc.add_topics``.\n\n\nAuthentication\n~~~~~~~~~~~~~~\n\nThe auth system works like in Django with decorators.\nFor details see the corresponding Django documentation.\n\n+--------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+\n| Decorator                                        | Django Equivalent                                                                                                                                                     |\n+==================================================+=======================================================================================================================================================================+\n| aiohttp_json_rpc.django.auth.login_required      | `django.contrib.auth.decorators.login_required \u003chttps://docs.djangoproject.com/en/1.8/topics/auth/default/#django.contrib.auth.decorators.login_required\u003e`_           |\n+--------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+\n| aiohttp_json_rpc.django.auth.permission_required | `django.contrib.auth.decorators.permission_required \u003chttps://docs.djangoproject.com/en/1.8/topics/auth/default/#django.contrib.auth.decorators.permission_required\u003e`_ |\n+--------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+\n| aiohttp_json_rpc.django.auth.user_passes_test    | `django.contrib.auth.decorators.user_passes_test \u003chttps://docs.djangoproject.com/en/1.8/topics/auth/default/#django.contrib.auth.decorators.user_passes_test\u003e`_       |\n+--------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+\n\n.. code-block:: python\n\n  from aiohttp_json_rpc.auth import (\n      permission_required,\n      user_passes_test,\n      login_required,\n  )\n\n  from aiohttp_json_rpc.auth.django import DjangoAuthBackend\n  from aiohttp_json_rpc import JsonRpc\n\n  @login_required\n  @permission_required('ping')\n  @user_passes_test(lambda user: user.is_superuser)\n  async def ping(request):\n      return 'pong'\n\n  if __name__ == '__main__':\n      rpc = JsonRpc(auth_backend=DjangoAuthBackend())\n\n      rpc.add_methods(\n          ('', ping),\n      )\n\n      rpc.add_topics(\n          ('foo', [login_required, permission_required('foo')])\n      )\n\n\nUsing SSL Connections\n~~~~~~~~~~~~~~~~~~~~~\nIf you need to setup a secure RPC server (use own certification files for example) you can create a ssl.SSLContext instance and pass it into the aiohttp web application. \n\nThe following code implements a simple secure RPC server that serves the method ``ping`` on ``localhost:8080``\n\n.. code-block:: python\n\n  from aiohttp.web import Application, run_app\n  from aiohttp_json_rpc import JsonRpc\n  import asyncio\n  import ssl\n\n\n  async def ping(request):\n      return 'pong'\n\n\n  if __name__ == '__main__':\n      loop = asyncio.get_event_loop()\n\n      rpc = JsonRpc()\n      rpc.add_methods(\n          ('', ping),\n      )\n      \n      app = Application(loop=loop)\n      app.router.add_route('*', '/', rpc.handle_request)\n      \n      ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n      ssl_context.load_cert_chain('path/to/server.crt', 'path/to/server.key')\n\n      run_app(app, host='0.0.0.0', port=8080, ssl_context=ssl_context)\n\nThe following code implements a secure RPC client using the ``JsonRpcClient`` Python client.\n\n.. code-block:: python\n\n  from aiohttp_json_rpc import JsonRpcClient\n  import ssl\n\n  async def ping_json_rpc():\n      \"\"\"Connect to wss://localhost:8080/, call ping() and disconnect.\"\"\"\n      rpc_client = JsonRpcClient()\n      ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n      ssl_context.load_cert_chain('path/to/server.crt','path/to/server.key')\n      try:\n          await rpc_client.connect('localhost', 8080, ssl=ssl_context)\n          call_result = await rpc_client.call('ping')\n          print(call_result)  # prints 'pong' (if that's return val of ping)\n      finally:\n          await rpc_client.disconnect()\n\n\n  asyncio.get_event_loop().run_until_complete(ping_json_rpc())\n\nSee `aiohttp documentation \u003chttps://docs.aiohttp.org/en/stable/client_advanced.html#ssl-control-for-tcp-sockets\u003e`_ for more details on SSL control for TCP sockets.\n\n\nClass References\n----------------\n\nclass aiohttp_json_rpc.JsonRpc(object)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nMethods\n'''''''\n\n``def add_methods(self, *args, prefix='')``\n  Args have to be tuple containing a prefix as string (may be empty) and a module,\n  object, coroutine or import string.\n\n  If second arg is module or object all coroutines in it are getting added.\n\n``async def get_methods()``\n  Returns list of all available RPC methods.\n\n``def filter(self, topics)``\n  Returns generator over all clients that have subscribed for given topic.\n\n  Topics can be string or a list of strings.\n\n``async def notify(self, topic, data)``\n  Send RPC notification to all connected clients subscribed to given topic.\n\n  Data has to be JSON serializable.\n\n  Uses ``filter()``.\n\n``async def subscribe(topics)``\n  Subscribe to a topic.\n\n  Topics can be string or a list of strings.\n\n``async def unsubscribe(topics)``\n  Unsubscribe from a topic.\n\n  Topics can be string or a list of strings.\n\n``async def get_topics()``\n  Get subscribable  topics as list of strings.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpengutronix%2Faiohttp-json-rpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpengutronix%2Faiohttp-json-rpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpengutronix%2Faiohttp-json-rpc/lists"}