1  Why consider JSON‑RPC?

JSON‑RPC is a lightweight Remote Procedure Call protocol that serialises every request/response as a single JSON object and is transport‑agnostic (HTTP, WebSocket, raw TCP, message queues…). Compared with REST it removes URL/verb semantics and lets you call a remote function almost like a local one; compared with gRPC it keeps human‑readable payloads and a near‑zero learning curve.

Typical request:

{ "jsonrpc": "2.0", "method": "add", "params": [5, 3], "id": 1 }

Typical success reply:

{ "jsonrpc": "2.0", "result": 8, "id": 1 }

If id is omitted the call is a “notification” and the server must not reply.


2  Protocol in one picture (PlantUML)

@startuml
actor "Service A\n(client)" as A
participant "Service B\n(server)" as B
A -> B : POST /rpc \n{jsonrpc:2.0, method:add, params:[5,3], id:1}
B -> B : add(5,3)
B --> A : {jsonrpc:2.0, result:8, id:1}
@enduml

Batching (array of calls in a single POST) and notifications (fire‑and‑forget) are part of the 2.0 spec.


3  Quick comparison

   JSON‑RPC REST gRPC
Message format JSON (text) JSON / XML Protobuf (binary)
API model Functions Resources (noun + verb) Functions
Streaming (HTTP/2)
Human readable
Code‑gen / IDL None Swagger / OpenAPI .proto
Raw performance ◎ (fastest)
Tooling mind‑share Medium Huge High

Use JSON‑RPC when the call graph is naturally verb‑centric (micro‑services cooperating via small, well‑defined procedures) and you want a payload anyone can read with curl.


4  Library landscape (2025)

Library Latest release Python support Django support Notes
django‑modern‑rpc 1.1.0 Jan 2025 3.7 → 3.13 2.2 → 5.1 Multi‑entry‑point, JSON‑RPC 2.0 only, built‑in auth & HTML docs
tinyrpc 1.1.7 Jul 2023 3.x framework‑agnostic Modular transports (HTTP, WS, ZeroMQ, RabbitMQ, …)
jsonrpcserver 5.0.9 Sep 2022 3.8 → 3.10 One‑file HTTP helpers, good for small services
json‑rpc 1.15.0 Jun 2023 2.6 → 3.8 (classifiers); runs 3.9+ Optional Django 1.x Pure protocol implementation, use when you embed your own transport

Recommendation
Django 4/5 projects: django‑modern‑rpc.
Framework‑mix or multiple transports: tinyrpc.
Tiny one‑off HTTP service: jsonrpcserver.


5  Hands‑on code

5.1 Python standalone server & client (tinyrpc)

# server.py  (gevent WSGI HTTP)
from gevent import pywsgi, queue
from tinyrpc.server.gevent import RPCServerGreenlets
from tinyrpc.transports.wsgi import WsgiServerTransport
from tinyrpc.protocols.jsonrpc import JSONRPCProtocol
from tinyrpc.dispatch import RPCDispatcher

disp = RPCDispatcher()

@disp.public
def add(a: int, b: int) -> int:
    return a + b

transport = WsgiServerTransport(queue_class=queue.Queue)
wsgi = pywsgi.WSGIServer(("0.0.0.0", 5000), transport.handle)
rpc_srv = RPCServerGreenlets(transport, JSONRPCProtocol(), disp)

wsgi.start()
rpc_srv.serve_forever()
# client.py
from tinyrpc import RPCClient
from tinyrpc.protocols.jsonrpc import JSONRPCProtocol
from tinyrpc.transports.http import HttpPostClientTransport

rpc = RPCClient(JSONRPCProtocol(),
                HttpPostClientTransport("http://localhost:5000/"))
proxy = rpc.get_proxy()
print(proxy.add(5, 3))          # → 8

5.2 Django 4/5 with django‑modern‑rpc

pip install django-modern-rpc
# settings.py
INSTALLED_APPS += ["modernrpc"]

MODERNRPC_METHODS_MODULES = [
    'rpcapp.rpc_methods',
]
# urls.py
from modernrpc.views import JSONRPCEntryPoint

urlpatterns += [
    path("rpc/", JSONRPCEntryPoint.as_view(), name="jsonrpc"),
]
# myapp/rpc_methods.py
from modernrpc.core import rpc_method

@rpc_method  # visible at /rpc/
def add(a: int, b: int) -> int:
    return a + b

5.3 Source code

Check out the source code and read README.md for more details on how to run and test:
https://gitlab.com/cuong-labs/jsonrpcdjangolab

6  Hardening for production

  1. Transport security – always HTTPS; if internal only, still require TLS within cluster.
  2. Authentication & authorisation – JWT or mutual‑TLS; modernrpc provides @rpc_method(auth="token").
  3. Rate limiting & API gateway – NGINX, Kong, or Envoy in front; defend against method‑spam.
  4. Observability – log method, id, latency, error code; expose Prometheus counters.
  5. Timeouts & retries – client: connect‑timeout 2–3 s, total 5–10 s; exponential back‑off ensure idempotent operations or deduplicate by id.
  6. Batch & notification – use batch for fan‑out calls; use notification for fire‑and‑forget (logging, metrics).
  7. When to upgrade to gRPC – need bi‑directional streaming, very high QPS, or strict IDL & code‑gen across many languages.

7  Wrap‑up

JSON‑RPC 2.0 hits a sweet spot for function‑centric micro‑services that prefer simplicity over the full REST verb set and don’t need gRPC’s binary speed or streaming.

  • django‑modern‑rpc gives first‑class JSON‑RPC on Django 4/5 with docs & auth.
  • tinyrpc excels when you mix Python frameworks or want ZeroMQ/RabbitMQ transport.

💬 Bình luận