FastAPI JSON-RPC 2.0 + OpenRPC 1.0 service discovery plugin
Project description
fastapi-openrpc
Declarative JSON-RPC 2.0 interface and OpenRPC 1.0 service discovery for FastAPI applications.
Features
- Declarative Registration —
@method()decorator with automatic JSON Schema inference - OpenRPC Service Discovery —
GET /openrpc.jsonreturns complete OpenRPC document - Pydantic Support — Automatic schema generation with
$refreferences - RpcContext Propagation — Secure caller context injection via FastAPI
Depends() - HMAC Authentication — Built-in signature verification with Nonce replay protection
- Role-Based Authorization — Method-level role declarations with composition semantics
Installation
pip install fastapi-openrpc
Optional dependencies:
# Redis support (Nonce replay protection)
pip install fastapi-openrpc[redis]
# Development dependencies
pip install fastapi-openrpc[dev]
Quick Start
from fastapi import FastAPI
from fastapi_openrpc import OpenRpcRouter, RpcContext, method
app = FastAPI()
openrpc_router = OpenRpcRouter(
title="My API",
version="1.0.0",
description="My JSON-RPC service",
)
@method(name="getUser")
async def get_user(ctx: RpcContext, user_id: str) -> dict:
"""Get user information by user_id."""
return {"id": user_id, "name": "Alice", "roles": ctx.roles}
@method(name="listUsers")
async def list_users(ctx: RpcContext, limit: int = 10) -> list[dict]:
"""Return a list of users."""
return [{"id": i, "name": f"User {i}"} for i in range(limit)]
app.include_router(openrpc_router)
After starting the server, access GET /openrpc.json to view the OpenRPC service document.
Authentication
HMAC Authentication
from fastapi_openrpc.authentication import HMACAuthentication
auth = HMACAuthentication(secret_key="your-secret-key")
openrpc_router = OpenRpcRouter(
authentication=auth,
)
Nonce Replay Protection
auth = HMACAuthentication(
secret_key="your-secret-key",
enable_nonce=True,
redis_url="redis://localhost:6379",
nonce_ttl=3600,
redis_required=True, # Reject requests when Redis is unavailable
connect_timeout=2.0, # Redis connection timeout (seconds)
operation_timeout=5.0, # Redis operation timeout (seconds)
cleanup_timeout=2.0, # Redis cleanup timeout (seconds)
)
Header format:
{
"roles": ["admin"],
"nonce": "550e8400-e29b-41d4-a716-446655440000"
}
Authorization
from fastapi_openrpc import Require
@method(name="adminAction", required_roles=["admin"])
async def admin_action(ctx: RpcContext) -> dict:
"""Admin only."""
return {"status": "done"}
@method(name="editContent", required_roles=["editor", "admin"], require=Require.ALL)
async def edit_content(ctx: RpcContext) -> dict:
"""Requires both editor and admin roles."""
return {"status": "edited"}
Error Handling
from fastapi_openrpc import InvalidParams, MethodNotFound
@method(name="divide")
async def divide(ctx: RpcContext, a: float, b: float) -> float:
if b == 0:
raise InvalidParams("Division by zero")
return a / b
Built-in error codes:
| Error | Code |
|---|---|
| Parse error | -32700 |
| Invalid Request | -32600 |
| Method Not Found | -32601 |
| Invalid Params | -32602 |
| Internal Error | -32603 |
| Forbidden | -32000 |
| Replay Detected | -32002 |
Library reserves -32000 ~ -32099, application custom errors start from -32100.
API Reference
OpenRpcRouter
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=4)
openrpc_router = OpenRpcRouter(
title="My API",
version="1.0.0",
description="...",
servers=[{"url": "https://api.example.com"}],
authentication=HMACAuthentication(secret_key="..."), # Optional
executor=executor, # Optional, for sync handler thread pool
)
app.include_router(openrpc_router)
@method() Decorator
@method(
name="myMethod", # RPC method name
tags=["admin"], # OpenRPC tags
summary="Short description",
deprecated=False,
required_roles=["admin"], # Required roles
require=Require.ALL, # Role composition semantics
)
async def my_handler(ctx: RpcContext, arg1: str, arg2: int = 10) -> dict:
return {"result": arg1}
Note:
ctx: RpcContextis a reserved parameter name for injecting caller context.
Usage Examples
# Call RPC method
curl -X POST http://localhost:8000/ \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "getUser", "params": {"user_id": "42"}}'
# Service discovery
curl http://localhost:8000/openrpc.json
Documentation
For detailed user documentation, see docs/index.md.
Additional guides:
- Tutorial: Pydantic Models — 4 scenarios covering flat params, nested models, optional fields, and validation
- How-to: Error Handling — custom errors, Nonce replay protection, best practices
- Explanation: Concurrency Model — ThreadPoolExecutor, sync handler wrapping, closure safety
Contributing
Issues and Pull Requests are welcome.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_openrpc-0.1.4.tar.gz.
File metadata
- Download URL: fastapi_openrpc-0.1.4.tar.gz
- Upload date:
- Size: 125.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4160f554705b0f2450872636dd7453b81730cba87be5543659c332aa7b51da7d
|
|
| MD5 |
30d343b1ff5ed9315bc63f3381524326
|
|
| BLAKE2b-256 |
72ac92caa95bf6ca425ee8d6371bb2e8c566a0a410cb07ba63ca342e458d2c69
|
File details
Details for the file fastapi_openrpc-0.1.4-py3-none-any.whl.
File metadata
- Download URL: fastapi_openrpc-0.1.4-py3-none-any.whl
- Upload date:
- Size: 30.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70e89340c2a4847d4e5d75dff9b4f2893f0615ca92f8b38de675597821e274ce
|
|
| MD5 |
9b95a358b19d0903c71f48fb20ec0197
|
|
| BLAKE2b-256 |
cdee4575a94b83ddc4e68ac31d3168f59094f4730d9c9a8d6694d7e08ffa3839
|