python-jsonrpc-lib 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_jsonrpc_lib-0.3.1/.claude/skills/jsonrpc-lib/SKILL.md +198 -0
- python_jsonrpc_lib-0.3.1/.github/workflows/docs.yml +19 -0
- python_jsonrpc_lib-0.3.1/.gitignore +8 -0
- python_jsonrpc_lib-0.3.1/LICENSE +21 -0
- python_jsonrpc_lib-0.3.1/MANIFEST.in +5 -0
- python_jsonrpc_lib-0.3.1/PKG-INFO +141 -0
- python_jsonrpc_lib-0.3.1/README.md +110 -0
- python_jsonrpc_lib-0.3.1/docs/advanced/async.md +229 -0
- python_jsonrpc_lib-0.3.1/docs/advanced/batch.md +266 -0
- python_jsonrpc_lib-0.3.1/docs/advanced/middleware.md +264 -0
- python_jsonrpc_lib-0.3.1/docs/advanced/protocols.md +264 -0
- python_jsonrpc_lib-0.3.1/docs/api-reference.md +517 -0
- python_jsonrpc_lib-0.3.1/docs/index.md +149 -0
- python_jsonrpc_lib-0.3.1/docs/integrations/custom.md +351 -0
- python_jsonrpc_lib-0.3.1/docs/integrations/fastapi.md +452 -0
- python_jsonrpc_lib-0.3.1/docs/integrations/flask.md +296 -0
- python_jsonrpc_lib-0.3.1/docs/philosophy.md +337 -0
- python_jsonrpc_lib-0.3.1/docs/tutorial/01-hello-world.md +102 -0
- python_jsonrpc_lib-0.3.1/docs/tutorial/02-method-classes.md +167 -0
- python_jsonrpc_lib-0.3.1/docs/tutorial/03-parameters.md +298 -0
- python_jsonrpc_lib-0.3.1/docs/tutorial/04-nested-types.md +401 -0
- python_jsonrpc_lib-0.3.1/docs/tutorial/05-context.md +320 -0
- python_jsonrpc_lib-0.3.1/docs/tutorial/06-groups.md +195 -0
- python_jsonrpc_lib-0.3.1/docs/tutorial/07-openapi.md +532 -0
- python_jsonrpc_lib-0.3.1/mkdocs.yml +72 -0
- python_jsonrpc_lib-0.3.1/pyproject.toml +77 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/__init__.py +83 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/errors.py +131 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/jsonrpc.py +881 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/method.py +561 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/openapi.py +505 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/py.typed +0 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/request.py +164 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/response.py +169 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/types.py +53 -0
- python_jsonrpc_lib-0.3.1/src/jsonrpc/validation.py +297 -0
- python_jsonrpc_lib-0.3.1/tests/__init__.py +1 -0
- python_jsonrpc_lib-0.3.1/tests/fixtures.py +307 -0
- python_jsonrpc_lib-0.3.1/tests/test_context.py +751 -0
- python_jsonrpc_lib-0.3.1/tests/test_decorator.py +434 -0
- python_jsonrpc_lib-0.3.1/tests/test_internal_api.py +801 -0
- python_jsonrpc_lib-0.3.1/tests/test_jsonrpc_v1.py +661 -0
- python_jsonrpc_lib-0.3.1/tests/test_jsonrpc_v2.py +1238 -0
- python_jsonrpc_lib-0.3.1/tests/test_openapi.py +1025 -0
- python_jsonrpc_lib-0.3.1/tests/test_utils.py +1056 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: python-jsonrpc-lib
|
|
3
|
+
description: Use when writing code that uses the python-jsonrpc-lib library — creating RPC methods, registering them, organizing with groups, handling errors, or adding context and middleware.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# python-jsonrpc-lib usage guide
|
|
8
|
+
|
|
9
|
+
## Always use Method classes
|
|
10
|
+
|
|
11
|
+
**Never use the `@rpc.method` decorator** unless explicitly prototyping. It has no context, no middleware, no MethodGroup support, and is unsuitable for production. Default to `Method` subclasses:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from jsonrpc import JSONRPC, Method
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class AddParams:
|
|
19
|
+
a: int
|
|
20
|
+
b: int
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class AddResult:
|
|
24
|
+
sum: int
|
|
25
|
+
|
|
26
|
+
class Add(Method):
|
|
27
|
+
def execute(self, params: AddParams) -> AddResult:
|
|
28
|
+
return AddResult(sum=params.a + params.b)
|
|
29
|
+
|
|
30
|
+
rpc = JSONRPC(version='2.0')
|
|
31
|
+
rpc.register('add', Add())
|
|
32
|
+
|
|
33
|
+
response = rpc.handle('{"jsonrpc":"2.0","method":"add","params":{"a":1,"b":2},"id":1}')
|
|
34
|
+
# '{"jsonrpc": "2.0", "result": {"sum": 3}, "id": 1}'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## execute() rules
|
|
38
|
+
|
|
39
|
+
- `params` type **must be a dataclass** — never `dict`, `list`, or `TypedDict`
|
|
40
|
+
- `params` is always the second parameter and must be named `params` exactly
|
|
41
|
+
- Return type annotation is **required**
|
|
42
|
+
- For structured return values, **prefer a dataclass** over returning a raw dict
|
|
43
|
+
- Optional third parameter `context: ContextType` for per-request data
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
# Wrong — TypeError at class definition time
|
|
47
|
+
class Bad(Method):
|
|
48
|
+
def execute(self, params: dict) -> dict:
|
|
49
|
+
return {"result": params["x"]}
|
|
50
|
+
|
|
51
|
+
# Wrong — no return type
|
|
52
|
+
class AlsoBad(Method):
|
|
53
|
+
def execute(self, params: SomeParams):
|
|
54
|
+
return 42
|
|
55
|
+
|
|
56
|
+
# Correct
|
|
57
|
+
@dataclass
|
|
58
|
+
class SomeParams:
|
|
59
|
+
x: int
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class SomeResult:
|
|
63
|
+
value: int
|
|
64
|
+
label: str
|
|
65
|
+
|
|
66
|
+
class Good(Method):
|
|
67
|
+
def execute(self, params: SomeParams) -> SomeResult:
|
|
68
|
+
return SomeResult(value=params.x * 2, label="doubled")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## MethodGroup — namespacing and middleware
|
|
72
|
+
|
|
73
|
+
`MethodGroup()` takes no arguments. Name is set during registration.
|
|
74
|
+
Always pass an **instance**, not a class.
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from jsonrpc import JSONRPC, Method, MethodGroup
|
|
78
|
+
|
|
79
|
+
math = MethodGroup()
|
|
80
|
+
math.register('add', Add()) # instance, not Add
|
|
81
|
+
math.register('subtract', Sub())
|
|
82
|
+
|
|
83
|
+
rpc = JSONRPC(version='2.0')
|
|
84
|
+
rpc.register('math', math)
|
|
85
|
+
# Available: "math.add", "math.subtract"
|
|
86
|
+
|
|
87
|
+
# Nested groups
|
|
88
|
+
admin = MethodGroup()
|
|
89
|
+
users = MethodGroup()
|
|
90
|
+
users.register('create', CreateUser())
|
|
91
|
+
admin.register('users', users)
|
|
92
|
+
rpc.register('admin', admin)
|
|
93
|
+
# Available: "admin.users.create"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Context — per-request data
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from dataclasses import dataclass
|
|
100
|
+
from jsonrpc import JSONRPC, Method, JSONRPCError
|
|
101
|
+
|
|
102
|
+
@dataclass
|
|
103
|
+
class AuthContext:
|
|
104
|
+
user_id: int
|
|
105
|
+
is_admin: bool
|
|
106
|
+
|
|
107
|
+
@dataclass
|
|
108
|
+
class DeleteParams:
|
|
109
|
+
resource_id: int
|
|
110
|
+
|
|
111
|
+
class DeleteResource(Method):
|
|
112
|
+
def execute(self, params: DeleteParams, context: AuthContext) -> str:
|
|
113
|
+
if not context.is_admin:
|
|
114
|
+
raise JSONRPCError("Forbidden", code=-32000)
|
|
115
|
+
return f"deleted {params.resource_id}"
|
|
116
|
+
|
|
117
|
+
rpc = JSONRPC(version='2.0', context_type=AuthContext)
|
|
118
|
+
rpc.register('delete', DeleteResource())
|
|
119
|
+
|
|
120
|
+
ctx = AuthContext(user_id=42, is_admin=True)
|
|
121
|
+
response = rpc.handle(json_string, context=ctx)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Middleware via MethodGroup
|
|
125
|
+
|
|
126
|
+
Override `execute_method()` to add cross-cutting behavior:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
import time
|
|
130
|
+
from jsonrpc import MethodGroup
|
|
131
|
+
|
|
132
|
+
class TimingGroup(MethodGroup):
|
|
133
|
+
def execute_method(self, method, params, context=None):
|
|
134
|
+
start = time.time()
|
|
135
|
+
result = super().execute_method(method, params, context)
|
|
136
|
+
print(f"{method.__class__.__name__}: {time.time() - start:.4f}s")
|
|
137
|
+
return result
|
|
138
|
+
|
|
139
|
+
group = TimingGroup()
|
|
140
|
+
group.register('add', Add())
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Async
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
class AsyncFetch(Method):
|
|
147
|
+
async def execute(self, params: FetchParams) -> FetchResult:
|
|
148
|
+
data = await some_async_call(params.url)
|
|
149
|
+
return FetchResult(data=data)
|
|
150
|
+
|
|
151
|
+
response = await rpc.handle_async(json_string)
|
|
152
|
+
response = await rpc.handle_async(json_string, context=ctx)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Errors
|
|
156
|
+
|
|
157
|
+
Raise from inside `execute()` to return a JSON-RPC error response:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from jsonrpc import JSONRPCError, ServerError
|
|
161
|
+
|
|
162
|
+
raise JSONRPCError("Something failed") # -32603 InternalError
|
|
163
|
+
raise ServerError("Rate limit exceeded", code=-32029) # implementation-defined
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Error classes and their codes:
|
|
167
|
+
|
|
168
|
+
| Code | Class |
|
|
169
|
+
|------|-------|
|
|
170
|
+
| -32700 | `ParseError` |
|
|
171
|
+
| -32600 | `InvalidRequestError` |
|
|
172
|
+
| -32601 | `MethodNotFoundError` |
|
|
173
|
+
| -32602 | `InvalidParamsError` |
|
|
174
|
+
| -32603 | `InternalError` |
|
|
175
|
+
| -32001 | `InvalidResultError` |
|
|
176
|
+
| -32000 to -32099 | `ServerError` |
|
|
177
|
+
|
|
178
|
+
## OpenAPI generation
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from jsonrpc import JSONRPC, OpenAPIGenerator
|
|
182
|
+
|
|
183
|
+
generator = OpenAPIGenerator(rpc, title='My API', version='1.0.0')
|
|
184
|
+
spec = generator.generate() # OpenAPI 3.0 dict
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Docstrings on `execute()` become method descriptions. Dataclass fields become parameters. Optional fields (with defaults) are marked not-required automatically.
|
|
188
|
+
|
|
189
|
+
## Common mistakes
|
|
190
|
+
|
|
191
|
+
| Wrong | Right |
|
|
192
|
+
|-------|-------|
|
|
193
|
+
| `group.register(MyMethod)` | `group.register('name', MyMethod())` |
|
|
194
|
+
| `MethodGroup(prefix='math')` | `MethodGroup()` — no arguments |
|
|
195
|
+
| `params: dict` or `params: list` | `params: MyDataclass` |
|
|
196
|
+
| No return type annotation | `-> MyResult:` required |
|
|
197
|
+
| `rpc.handle(data_dict)` | `rpc.handle(json_string)` — JSON string only |
|
|
198
|
+
| `def execute(self, data: Params)` | `def execute(self, params: Params)` — must be `params` |
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Deploy docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
deploy:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: '3.12'
|
|
18
|
+
- run: pip install mkdocs mkdocs-material
|
|
19
|
+
- run: mkdocs gh-deploy --force
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Author
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-jsonrpc-lib
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Simple, yet solid - Type-safe JSON-RPC 1.0/2.0 with OpenAPI support
|
|
5
|
+
Project-URL: Homepage, https://github.com/uandysmith/python-jsonrpc-lib
|
|
6
|
+
Project-URL: Documentation, https://uandysmith.github.io/python-jsonrpc-lib/
|
|
7
|
+
Project-URL: Repository, https://github.com/uandysmith/python-jsonrpc-lib
|
|
8
|
+
Project-URL: Issues, https://github.com/uandysmith/python-jsonrpc-lib/issues
|
|
9
|
+
Author: Andy Smith
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: dataclass,json-rpc,jsonrpc,protocol,rpc,validation
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.15.0; extra == 'dev'
|
|
27
|
+
Provides-Extra: docs
|
|
28
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
|
|
29
|
+
Requires-Dist: mkdocs>=1.5.0; extra == 'docs'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# python-jsonrpc-lib
|
|
33
|
+
|
|
34
|
+
**Simple, yet solid.** JSON-RPC 1.0/2.0 for Python.
|
|
35
|
+
|
|
36
|
+
JSON-RPC is a small protocol: a method name, some parameters, a result. python-jsonrpc-lib keeps it that way. You write ordinary Python functions and dataclasses; the library handles validation, routing, error responses, and API documentation. No framework lock-in, no external dependencies, no boilerplate.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install python-jsonrpc-lib
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quickstart
|
|
45
|
+
|
|
46
|
+
Define methods as classes with typed parameters. The library validates inputs, routes calls, and builds responses automatically.
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from dataclasses import dataclass
|
|
50
|
+
from jsonrpc import JSONRPC, Method, MethodGroup
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class AddParams:
|
|
54
|
+
a: int
|
|
55
|
+
b: int
|
|
56
|
+
|
|
57
|
+
class Add(Method):
|
|
58
|
+
def execute(self, params: AddParams) -> int:
|
|
59
|
+
return params.a + params.b
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class GreetParams:
|
|
63
|
+
name: str
|
|
64
|
+
greeting: str = 'Hello'
|
|
65
|
+
|
|
66
|
+
class Greet(Method):
|
|
67
|
+
def execute(self, params: GreetParams) -> str:
|
|
68
|
+
return f'{params.greeting}, {params.name}!'
|
|
69
|
+
|
|
70
|
+
rpc = JSONRPC(version='2.0')
|
|
71
|
+
rpc.register('add', Add())
|
|
72
|
+
rpc.register('greet', Greet())
|
|
73
|
+
|
|
74
|
+
response = rpc.handle('{"jsonrpc": "2.0", "method": "add", "params": {"a": 5, "b": 3}, "id": 1}')
|
|
75
|
+
# '{"jsonrpc": "2.0", "result": 8, "id": 1}'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Pass in a JSON string, get a JSON string back. What carries it over the wire is up to you.
|
|
79
|
+
|
|
80
|
+
If `a` is `"five"` instead of `5`, the caller receives a `-32602 Invalid params` error immediately — no exception handling on your end.
|
|
81
|
+
|
|
82
|
+
The same `AddParams` dataclass drives validation, IDE autocomplete, and the OpenAPI schema.
|
|
83
|
+
|
|
84
|
+
## Why python-jsonrpc-lib?
|
|
85
|
+
|
|
86
|
+
- **Zero dependencies** — pure Python 3.11+. Nothing to pin, nothing to audit beyond the library itself.
|
|
87
|
+
- **Type validation from dataclasses** — declare parameters as a dataclass, get automatic validation and clear error messages for free.
|
|
88
|
+
- **OpenAPI docs auto-generated** — type hints and docstrings you already wrote become a full OpenAPI 3.0 spec. Point any Swagger-compatible UI at it and your API is self-documented.
|
|
89
|
+
- **Transport-agnostic** — `rpc.handle(json_string)` returns a string. HTTP, WebSocket, TCP, message queue: your choice.
|
|
90
|
+
- **Spec-compliant by default** — v1.0 and v2.0 rules enforced out of the box, configurable when you need to support legacy clients.
|
|
91
|
+
|
|
92
|
+
## Namespacing and Middleware
|
|
93
|
+
|
|
94
|
+
Use `MethodGroup` to organize methods into namespaces and add cross-cutting concerns:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
math = MethodGroup()
|
|
98
|
+
math.register('add', Add())
|
|
99
|
+
|
|
100
|
+
rpc = JSONRPC(version='2.0')
|
|
101
|
+
rpc.register('math', math)
|
|
102
|
+
|
|
103
|
+
# "math.add" is now available
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Quick Prototyping
|
|
107
|
+
|
|
108
|
+
For scripts and throwaway code, the `@rpc.method` decorator registers functions directly (v2.0 only):
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
rpc = JSONRPC(version='2.0')
|
|
112
|
+
|
|
113
|
+
@rpc.method
|
|
114
|
+
def add(a: int, b: int) -> int:
|
|
115
|
+
return a + b
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
For production use, prefer `Method` classes — they support context, middleware, and groups.
|
|
119
|
+
|
|
120
|
+
## Documentation
|
|
121
|
+
|
|
122
|
+
Full documentation with tutorials, integration guides, and API reference:
|
|
123
|
+
|
|
124
|
+
- [Tutorial: Hello World](docs/tutorial/01-hello-world.md) — first method, explained
|
|
125
|
+
- [Tutorial: Parameters](docs/tutorial/03-parameters.md) — dataclass validation in detail
|
|
126
|
+
- [Tutorial: Context](docs/tutorial/05-context.md) — authentication and per-request data
|
|
127
|
+
- [Tutorial: OpenAPI](docs/tutorial/07-openapi.md) — interactive API documentation
|
|
128
|
+
- [Flask integration](docs/integrations/flask.md)
|
|
129
|
+
- [FastAPI integration](docs/integrations/fastapi.md)
|
|
130
|
+
- [Philosophy](docs/philosophy.md) — design decisions and trade-offs
|
|
131
|
+
- [API Reference](docs/api-reference.md)
|
|
132
|
+
|
|
133
|
+
## Claude Code Integration
|
|
134
|
+
|
|
135
|
+
If you use [Claude Code](https://claude.ai/claude-code), a skill for this library is available. It gives Claude built-in knowledge of jsonrpc-lib's API: creating methods, registering them, organizing with groups, handling errors, and adding context and middleware — without having to look up docs.
|
|
136
|
+
|
|
137
|
+
To use it, add the skill file to your project's `.claude/skills/` directory.
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# python-jsonrpc-lib
|
|
2
|
+
|
|
3
|
+
**Simple, yet solid.** JSON-RPC 1.0/2.0 for Python.
|
|
4
|
+
|
|
5
|
+
JSON-RPC is a small protocol: a method name, some parameters, a result. python-jsonrpc-lib keeps it that way. You write ordinary Python functions and dataclasses; the library handles validation, routing, error responses, and API documentation. No framework lock-in, no external dependencies, no boilerplate.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install python-jsonrpc-lib
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
Define methods as classes with typed parameters. The library validates inputs, routes calls, and builds responses automatically.
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from jsonrpc import JSONRPC, Method, MethodGroup
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class AddParams:
|
|
23
|
+
a: int
|
|
24
|
+
b: int
|
|
25
|
+
|
|
26
|
+
class Add(Method):
|
|
27
|
+
def execute(self, params: AddParams) -> int:
|
|
28
|
+
return params.a + params.b
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class GreetParams:
|
|
32
|
+
name: str
|
|
33
|
+
greeting: str = 'Hello'
|
|
34
|
+
|
|
35
|
+
class Greet(Method):
|
|
36
|
+
def execute(self, params: GreetParams) -> str:
|
|
37
|
+
return f'{params.greeting}, {params.name}!'
|
|
38
|
+
|
|
39
|
+
rpc = JSONRPC(version='2.0')
|
|
40
|
+
rpc.register('add', Add())
|
|
41
|
+
rpc.register('greet', Greet())
|
|
42
|
+
|
|
43
|
+
response = rpc.handle('{"jsonrpc": "2.0", "method": "add", "params": {"a": 5, "b": 3}, "id": 1}')
|
|
44
|
+
# '{"jsonrpc": "2.0", "result": 8, "id": 1}'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Pass in a JSON string, get a JSON string back. What carries it over the wire is up to you.
|
|
48
|
+
|
|
49
|
+
If `a` is `"five"` instead of `5`, the caller receives a `-32602 Invalid params` error immediately — no exception handling on your end.
|
|
50
|
+
|
|
51
|
+
The same `AddParams` dataclass drives validation, IDE autocomplete, and the OpenAPI schema.
|
|
52
|
+
|
|
53
|
+
## Why python-jsonrpc-lib?
|
|
54
|
+
|
|
55
|
+
- **Zero dependencies** — pure Python 3.11+. Nothing to pin, nothing to audit beyond the library itself.
|
|
56
|
+
- **Type validation from dataclasses** — declare parameters as a dataclass, get automatic validation and clear error messages for free.
|
|
57
|
+
- **OpenAPI docs auto-generated** — type hints and docstrings you already wrote become a full OpenAPI 3.0 spec. Point any Swagger-compatible UI at it and your API is self-documented.
|
|
58
|
+
- **Transport-agnostic** — `rpc.handle(json_string)` returns a string. HTTP, WebSocket, TCP, message queue: your choice.
|
|
59
|
+
- **Spec-compliant by default** — v1.0 and v2.0 rules enforced out of the box, configurable when you need to support legacy clients.
|
|
60
|
+
|
|
61
|
+
## Namespacing and Middleware
|
|
62
|
+
|
|
63
|
+
Use `MethodGroup` to organize methods into namespaces and add cross-cutting concerns:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
math = MethodGroup()
|
|
67
|
+
math.register('add', Add())
|
|
68
|
+
|
|
69
|
+
rpc = JSONRPC(version='2.0')
|
|
70
|
+
rpc.register('math', math)
|
|
71
|
+
|
|
72
|
+
# "math.add" is now available
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Quick Prototyping
|
|
76
|
+
|
|
77
|
+
For scripts and throwaway code, the `@rpc.method` decorator registers functions directly (v2.0 only):
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
rpc = JSONRPC(version='2.0')
|
|
81
|
+
|
|
82
|
+
@rpc.method
|
|
83
|
+
def add(a: int, b: int) -> int:
|
|
84
|
+
return a + b
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For production use, prefer `Method` classes — they support context, middleware, and groups.
|
|
88
|
+
|
|
89
|
+
## Documentation
|
|
90
|
+
|
|
91
|
+
Full documentation with tutorials, integration guides, and API reference:
|
|
92
|
+
|
|
93
|
+
- [Tutorial: Hello World](docs/tutorial/01-hello-world.md) — first method, explained
|
|
94
|
+
- [Tutorial: Parameters](docs/tutorial/03-parameters.md) — dataclass validation in detail
|
|
95
|
+
- [Tutorial: Context](docs/tutorial/05-context.md) — authentication and per-request data
|
|
96
|
+
- [Tutorial: OpenAPI](docs/tutorial/07-openapi.md) — interactive API documentation
|
|
97
|
+
- [Flask integration](docs/integrations/flask.md)
|
|
98
|
+
- [FastAPI integration](docs/integrations/fastapi.md)
|
|
99
|
+
- [Philosophy](docs/philosophy.md) — design decisions and trade-offs
|
|
100
|
+
- [API Reference](docs/api-reference.md)
|
|
101
|
+
|
|
102
|
+
## Claude Code Integration
|
|
103
|
+
|
|
104
|
+
If you use [Claude Code](https://claude.ai/claude-code), a skill for this library is available. It gives Claude built-in knowledge of jsonrpc-lib's API: creating methods, registering them, organizing with groups, handling errors, and adding context and middleware — without having to look up docs.
|
|
105
|
+
|
|
106
|
+
To use it, add the skill file to your project's `.claude/skills/` directory.
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT
|