All Projects → pengutronix → aiohttp-json-rpc

pengutronix / aiohttp-json-rpc

Licence: Apache-2.0 license
Implements JSON-RPC 2.0 using aiohttp

Programming Languages

python
139335 projects - #7 most used programming language
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to aiohttp-json-rpc

Aiohttp
Asynchronous HTTP client/server framework for asyncio and Python
Stars: ✭ 11,972 (+22070.37%)
Mutual labels:  http-client, aiohttp, http-server
Donkey
Modern Clojure HTTP server and client built for ease of use and performance
Stars: ✭ 199 (+268.52%)
Mutual labels:  http-client, http-server
Http Kit
http-kit is a minimalist, event-driven, high-performance Clojure HTTP server/client library with WebSocket and asynchronous support
Stars: ✭ 2,234 (+4037.04%)
Mutual labels:  http-client, http-server
go-sse
Fully featured, spec-compliant HTML5 server-sent events library
Stars: ✭ 165 (+205.56%)
Mutual labels:  http-client, http-server
Libhv
🔥 比libevent、libuv更易用的国产网络库。A c/c++ network library for developing TCP/UDP/SSL/HTTP/WebSocket client/server.
Stars: ✭ 3,355 (+6112.96%)
Mutual labels:  http-client, http-server
Http4s
A minimal, idiomatic Scala interface for HTTP
Stars: ✭ 2,173 (+3924.07%)
Mutual labels:  http-client, http-server
EthernetWebServer SSL
Simple TLS/SSL Ethernet WebServer, HTTP Client and WebSocket Client library for for AVR, Portenta_H7, Teensy, SAM DUE, SAMD21, SAMD51, STM32F/L/H/G/WB/MP1, nRF52 and RASPBERRY_PI_PICO boards using Ethernet shields W5100, W5200, W5500, ENC28J60 or Teensy 4.1 NativeEthernet/QNEthernet. It now supports Ethernet TLS/SSL Client. The library supports …
Stars: ✭ 40 (-25.93%)
Mutual labels:  http-client, http-server
Http4k
The Functional toolkit for Kotlin HTTP applications. http4k provides a simple and uniform way to serve, consume, and test HTTP services.
Stars: ✭ 1,883 (+3387.04%)
Mutual labels:  http-client, http-server
http4ts
Server as a Function http toolkit for TypeScript & JavaScript
Stars: ✭ 30 (-44.44%)
Mutual labels:  http-client, http-server
rawhttp
HTTP library to make it easy to deal with raw HTTP.
Stars: ✭ 156 (+188.89%)
Mutual labels:  http-client, http-server
Pyro-FileStreamBot
Stream Telegram files to web
Stars: ✭ 38 (-29.63%)
Mutual labels:  aiohttp, http-server
Httpp
Micro http server and client written in C++
Stars: ✭ 144 (+166.67%)
Mutual labels:  http-client, http-server
Python Simple Rest Client
Simple REST client for python 3.6+
Stars: ✭ 143 (+164.81%)
Mutual labels:  http-client, aiohttp
Zio Http
A scala library to write Http apps.
Stars: ✭ 162 (+200%)
Mutual labels:  http-client, http-server
BCA-Phantom
A multi-platform HTTP(S) Reverse Shell Server and Client in Python 3
Stars: ✭ 80 (+48.15%)
Mutual labels:  http-client, http-server
cpphttpstack
c++ api for http client & server
Stars: ✭ 30 (-44.44%)
Mutual labels:  http-client, http-server
Qtnetworkng
QtNetwork Next Generation. A coroutine based network framework for Qt/C++, with more simpler API than boost::asio.
Stars: ✭ 125 (+131.48%)
Mutual labels:  http-client, http-server
Fs2 Http
Http Server and client using fs2
Stars: ✭ 132 (+144.44%)
Mutual labels:  http-client, http-server
matador
Take your appclication by the horns
Stars: ✭ 59 (+9.26%)
Mutual labels:  http-client, http-server
waspy
WASP framework for Python
Stars: ✭ 43 (-20.37%)
Mutual labels:  http-client, http-server
https://img.shields.io/travis/com/pengutronix/aiohttp-json-rpc/master.svg?label=Linux%20build%20%40%20Travis%20CI

aiohttp-json-rpc

Implements JSON-RPC 2.0 Specification using aiohttp

Protocol Support
Websocket since v0.1
POST TODO
GET TODO

Installation

pip install aiohttp-json-rpc

Usage

RPC methods can be added by using rpc.add_method().

All RPC methods are getting passed a aiohttp_json_rpc.communicaton.JsonRpcRequest.

Server

The following code implements a simple RPC server that serves the method ping on localhost:8080.

from aiohttp.web import Application, run_app
from aiohttp_json_rpc import JsonRpc
import asyncio


async def ping(request):
    return 'pong'


if __name__ == '__main__':
    loop = asyncio.get_event_loop()

    rpc = JsonRpc()
    rpc.add_methods(
        ('', ping),
    )

    app = Application(loop=loop)
    app.router.add_route('*', '/', rpc.handle_request)

    run_app(app, host='0.0.0.0', port=8080)

Client (JS)

The following code implements a simple RPC client that connects to the server above and prints all incoming messages to the console.

<script src="//code.jquery.com/jquery-2.2.1.js"></script>
<script>
  var ws = new WebSocket("ws://localhost:8080");
  var message_id = 0;

  ws.onmessage = function(event) {
    console.log(JSON.parse(event.data));
  }

  function ws_call_method(method, params) {
    var request = {
      jsonrpc: "2.0",
      id: message_id,
      method: method,
      params: params
    }

    ws.send(JSON.stringify(request));
    message_id++;
  }
</script>

These are example responses the server would give if you call ws_call_method.

--> ws_call_method("get_methods")
<-- {"jsonrpc": "2.0", "result": ["get_methods", "ping"], "id": 1}

--> ws_call_method("ping")
<-- {"jsonrpc": "2.0", "method": "ping", "params": "pong", "id": 2}

Client (Python)

There's also Python client, which can be used as follows:

from aiohttp_json_rpc import JsonRpcClient


async def ping_json_rpc():
    """Connect to ws://localhost:8080/, call ping() and disconnect."""
    rpc_client = JsonRpcClient()
    try:
        await rpc_client.connect('localhost', 8080)
        call_result = await rpc_client.call('ping')
        print(call_result)  # prints 'pong' (if that's return val of ping)
    finally:
        await rpc_client.disconnect()


asyncio.get_event_loop().run_until_complete(ping_json_rpc())

Or use asynchronous context manager interface:

from aiohttp_json_rpc import JsonRpcClientContext


async def jrpc_coro():
    async with JsonRpcClientContext('ws://localhost:8000/rpc') as jrpc:
        # `some_other_method` will get request.params filled with `args` and
        # `kwargs` keys:
        method_res = await jrpc.some_other_method('arg1', key='arg2')

    return method_res

asyncio.get_event_loop().run_until_complete(jrpc_coro())

Features

Error Handling

All errors specified in the error specification but the InvalidParamsError are handled internally.

If your coroutine got called with wrong params you can raise an aiohttp_json_rpc.RpcInvalidParamsError instead of sending an error by yourself.

The JSONRPC protocol defines a range for server defined errors. aiohttp_json_rpc.RpcGenericServerDefinedError implements this feature.

from aiohttp_json_rpc import RpcInvalidParamsError


async def add(request):
    try:
        a = params.get('a')
        b = params.get('b')

        return a + b

    except KeyError:
        raise RpcInvalidParamsError


  async def add(request):
      raise RpcGenericServerDefinedError(
          error_code=-32050,
          message='Computer says no.',
      )

Error Logging

Every traceback caused by an RPC method will be caught and logged.

The RPC will send an RPC ServerError and proceed as if nothing happened.

async def divide(request):
    return 1 / 0  # will raise a ZeroDivisionError
ERROR:JsonRpc: Traceback (most recent call last):
ERROR:JsonRpc:   File "aiohttp_json_rpc/base.py", line 289, in handle_websocket_request
ERROR:JsonRpc:     rsp = yield from methods[msg['method']](ws, msg)
ERROR:JsonRpc:   File "./example.py", line 12, in divide
ERROR:JsonRpc:     return 1 / 0
ERROR:JsonRpc: ZeroDivisionError: division by zero

Publish Subscribe

Any client of an RPC object can subscribe to a topic using the built-in RPC method subscribe().

Topics can be added using rpc.add_topics.

Authentication

The auth system works like in Django with decorators. For details see the corresponding Django documentation.

Decorator Django Equivalent
aiohttp_json_rpc.django.auth.login_required django.contrib.auth.decorators.login_required
aiohttp_json_rpc.django.auth.permission_required django.contrib.auth.decorators.permission_required
aiohttp_json_rpc.django.auth.user_passes_test django.contrib.auth.decorators.user_passes_test
from aiohttp_json_rpc.auth import (
    permission_required,
    user_passes_test,
    login_required,
)

from aiohttp_json_rpc.auth.django import DjangoAuthBackend
from aiohttp_json_rpc import JsonRpc

@login_required
@permission_required('ping')
@user_passes_test(lambda user: user.is_superuser)
async def ping(request):
    return 'pong'

if __name__ == '__main__':
    rpc = JsonRpc(auth_backend=DjangoAuthBackend())

    rpc.add_methods(
        ('', ping),
    )

    rpc.add_topics(
        ('foo', [login_required, permission_required('foo')])
    )

Using SSL Connections

If 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.

The following code implements a simple secure RPC server that serves the method ping on localhost:8080

from aiohttp.web import Application, run_app
from aiohttp_json_rpc import JsonRpc
import asyncio
import ssl


async def ping(request):
    return 'pong'


if __name__ == '__main__':
    loop = asyncio.get_event_loop()

    rpc = JsonRpc()
    rpc.add_methods(
        ('', ping),
    )

    app = Application(loop=loop)
    app.router.add_route('*', '/', rpc.handle_request)

    ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    ssl_context.load_cert_chain('path/to/server.crt', 'path/to/server.key')

    run_app(app, host='0.0.0.0', port=8080, ssl_context=ssl_context)

The following code implements a secure RPC client using the JsonRpcClient Python client.

from aiohttp_json_rpc import JsonRpcClient
import ssl

async def ping_json_rpc():
    """Connect to wss://localhost:8080/, call ping() and disconnect."""
    rpc_client = JsonRpcClient()
    ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    ssl_context.load_cert_chain('path/to/server.crt','path/to/server.key')
    try:
        await rpc_client.connect('localhost', 8080, ssl=ssl_context)
        call_result = await rpc_client.call('ping')
        print(call_result)  # prints 'pong' (if that's return val of ping)
    finally:
        await rpc_client.disconnect()


asyncio.get_event_loop().run_until_complete(ping_json_rpc())

See aiohttp documentation for more details on SSL control for TCP sockets.

Class References

class aiohttp_json_rpc.JsonRpc(object)

Methods
def add_methods(self, *args, prefix='')

Args have to be tuple containing a prefix as string (may be empty) and a module, object, coroutine or import string.

If second arg is module or object all coroutines in it are getting added.

async def get_methods()
Returns list of all available RPC methods.
def filter(self, topics)

Returns generator over all clients that have subscribed for given topic.

Topics can be string or a list of strings.

async def notify(self, topic, data)

Send RPC notification to all connected clients subscribed to given topic.

Data has to be JSON serializable.

Uses filter().

async def subscribe(topics)

Subscribe to a topic.

Topics can be string or a list of strings.

async def unsubscribe(topics)

Unsubscribe from a topic.

Topics can be string or a list of strings.

async def get_topics()
Get subscribable topics as list of strings.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].