permitio / fastapi_websocket_rpc

⚡ FASTAPI Websocket RPC- A fast and durable bidirectional JSON RPC channel over Websockets.
https://permit.io
MIT License
194 stars 21 forks source link
asyncio fastapi fastapi-websocket-rpc python realtime-messaging rpc websockets

RPC

#

⚡ FASTAPI Websocket RPC

RPC over Websockets made easy, robust, and production ready

Tests

Package

Downloads

A fast and durable bidirectional JSON RPC channel over Websockets. The easiest way to create a live async channel between two nodes via Python (or other clients).

Supports and tested on Python >= 3.7

Installation 🛠️

pip install fastapi_websocket_rpc

RPC call example:

Say the server exposes an "add" method, e.g. :

class RpcCalculator(RpcMethodsBase):
    async def add(self, a, b):
        return a + b

Calling it is as easy as calling the method under the client's "other" property:

response = await client.other.add(a=1,b=2)
print(response.result) # 3

getting the response with the return value.

Usage example:

Server:

import uvicorn
from fastapi import FastAPI
from fastapi_websocket_rpc import RpcMethodsBase, WebsocketRPCEndpoint

# Methods to expose to the clients
class ConcatServer(RpcMethodsBase):
    async def concat(self, a="", b=""):
        return a + b

# Init the FAST-API app
app =  FastAPI()
# Create an endpoint and load it with the methods to expose
endpoint = WebsocketRPCEndpoint(ConcatServer())
# add the endpoint to the app
endpoint.register_route(app, "/ws")

# Start the server itself
uvicorn.run(app, host="0.0.0.0", port=9000)

Client

import asyncio
from fastapi_websocket_rpc import RpcMethodsBase, WebSocketRpcClient

async def run_client(uri):
    async with WebSocketRpcClient(uri, RpcMethodsBase()) as client:
        # call concat on the other side
        response = await client.other.concat(a="hello", b=" world")
        # print result
        print(response.result)  # will print "hello world"

# run the client until it completes interaction with server
asyncio.get_event_loop().run_until_complete(
    run_client("ws://localhost:9000/ws")
)

See the examples and tests folders for more server and client examples

Server calling client example:

What can I do with this?

Websockets are ideal to create bi-directional realtime connections over the web.

Concepts

Logging

fastapi-websocket-rpc provides a helper logging module to control how it produces logs for you. See fastapi_websocket_rpc/logger.py. Use logging_config.set_mode or the 'WS_RPC_LOGGING' environment variable to choose the logging method you prefer or override completely via default logging config.

example:

# set RPC to log like UVICORN
from fastapi_websocket_rpc.logger import logging_config, LoggingModes
logging_config.set_mode(LoggingModes.UVICORN)

HTTP(S) Proxy

By default, fastapi-websocket-rpc uses websockets module as websocket client handler. This does not support HTTP(S) Proxy, see https://github.com/python-websockets/websockets/issues/364 . If the ability to use a proxy is important to, another websocket client implementation can be used, e.g. websocket-client (https://websocket-client.readthedocs.io). Here is how to use it. Installation:

pip install websocket-client

Then use websocket_client_handler_cls parameter:

import asyncio
from fastapi_websocket_rpc import RpcMethodsBase, WebSocketRpcClient, ProxyEnabledWebSocketClientHandler

async def run_client(uri):
    async with WebSocketRpcClient(uri, RpcMethodsBase(), websocket_client_handler_cls = ProxyEnabledWebSocketClientHandler) as client:

Just set standard environment variables (lowercase and uppercase works): http_proxy, https_proxy, and no_proxy before running python script.

Pull requests - welcome!