[](https://pypi.python.org/pypi/simplejrpc/)
[](https://pypi.python.org/pypi/simplejrpc/)
[](https://pypi.org/project/simplejrpc/)
simplejrpc
==========
# 1. Getting Started Quickly
### 1.1 Install SDK
Install the SDK using pip:
```bash
pip3 install simplejrpc
```
> Once installed, you can import and use the SDK functions in your project.
---
# 2. Service Registration
### 2.1 Register a Socket File
Since the SDK communicates with the backend process via a **Unix Socket file** (based on the JSON-RPC 2.0 protocol), you must explicitly specify the `socket_path` to ensure the service generates a `.sock` file and exposes communication capabilities.
```python
# main.py
from simplejrpc import ServerApplication
# Specify the Unix Socket file path
socket_path = "/xxx/app.socket"
# Create the application instance
app = ServerApplication(socket_path=socket_path)
```
> ✅ Tip: Make sure the path is writable and does not conflict with other services.
---
### 2.2 Register a Configuration File (Logging System)
To enable logging, specify the path to a logger config file during initialization. You can also call `app.setup_logger(config_path)` after the app starts to load the logger config dynamically.
* Supported format: **YAML**
* If not configured, a simple logger provided by loguru is used by default.
```python
# main.py
from simplejrpc import ServerApplication
sock_path = "/xxx/app.sock"
config_path = "/xxx/config.yaml"
# Initialize the app with logger configuration
app = ServerApplication(socket_path=sock_path, config_path=config_path)
# Alternatively, configure the logger after initialization:
# app.setup_logger(config_path)
```
---
### 2.3 Register Methods (Business Routes)
Registering methods exposes functions as interfaces accessible via JSON-RPC.
#### ✅ Default Registration (Using Function Name)
If the method name is not explicitly specified, the system will use the function name by default:
```python
from simplejrpc.response import jsonify
@app.route() # Registered as 'hello' by default
async def hello():
return jsonify(data="hello", msg="OK")
```
#### ✅ Explicit Registration (Specify Method Name)
You can also specify a method name using the `name` parameter. It’s recommended to keep it consistent with the function name for maintainability:
```python
from simplejrpc.response import jsonify
@app.route(name="hello") # Explicitly set method name
async def hello():
return jsonify(data="hello", msg="OK")
```
> ⚠️ Note: If `name` differs from the function name, it may cause confusion during maintenance or calls. Consistent naming is advised.
---
# 3. Making Requests
---
## 3.1 Request and Response Structure
### ✅ Supported Parameter Formats
The framework supports two ways of receiving request parameters:
#### 📌 Explicit Parameter Declaration (Recommended)
Use when parameters are fixed and clearly named:
```python
@app.route(name="hello")
async def hello(lang, action):
# Directly receive request parameters lang and action
...
```
✅ Advantage: Clear typing, easier validation and maintenance.
---
#### 📌 Dynamic Parameter Handling (\*args, \*\*kwargs)
Use when the number of parameters is variable or needs generic processing:
```python
@app.route(name="hello")
async def hello(*args, **kwargs):
lang = kwargs.get("lang")
action = kwargs.get("action")
...
```
---
### ✅ Standard Response Format
All responses should be returned using `jsonify`, containing `code`, `data`, and `msg` fields:
```python
from simplejrpc.response import jsonify
@app.route(name="hello")
async def hello():
return jsonify(code=400, data=True, msg="Operation failed")
```
---
### ✅ Example Response Structure
#### Success Response:
```json
{
"jsonrpc": "2.0",
"result": {
"code": 200,
"meta": {
"endpoint": null,
"close": 1
},
"data": [],
"msg": "OK"
},
"id": 1
}
```
#### Error Response:
```json
{
"jsonrpc": "2.0",
"result": {
"code": 400,
"meta": {
"endpoint": null,
"close": 1
},
"data": null,
"msg": "expected value ['start', 'stop']"
},
"id": 1
}
```
---
## 3.2 Start the Service
Example server code:
```python
# main.py
import asyncio
from simplejrpc import ServerApplication
from simplejrpc.response import jsonify
socket_path = "/xxx/app.socket"
app = ServerApplication(socket_path)
@app.route(name="hello")
async def hello():
return jsonify(data="hello", msg="OK")
if __name__ == "__main__":
asyncio.run(app.run())
```
Start the service:
```bash
$ python3 main.py
```
---
## 3.3 Call Interface (Client Test)
Use the SDK's `Request` class for testing:
```python
from simplejrpc import Request
# Must match the socket path used by the server
socket_path = "/xxx/app.sock"
def test_hello():
method = "hello"
params = {
"lang": "zh-CN",
"action": "start"
}
request = Request(socket_path)
result = request.send_request(method, params)
print("[recv] >", result)
```
---
# 4. Making Requests
---
## 4.1 Form Validation
The SDK integrates [`wtforms`](https://wtforms.readthedocs.io/en/3.1.x/) to provide a simple yet powerful validation system with support for custom validators.
### ✅ Example: Define and Use a Form Class
```python
from simplejrpc.schemas import BaseForm, StrRangeValidator, simple
from simplejrpc.response import jsonify
# Custom form class, restricts 'action' to "start" or "stop"
class TestForm(BaseForm):
action = simple.StringField(
validators=[StrRangeValidator(allows=["start", "stop"])]
)
# Specify socket path and register app
socket_path = "/xxx/app.socket"
app = ServerApplication(socket_path)
# Specify 'form' to trigger validation automatically
@app.route(name="hello", form=TestForm)
async def hello(lang, action):
return jsonify(data=[1, 2, 3], msg="OK")
```
---
### ✅ Custom Validators
You can create custom validation logic by extending `BaseValidator`.
> A custom validator class must inherit from `BaseValidator` and implement the `validator(form, field)` method. Only two parameters are accepted: the form instance and the field instance.
```python
from simplejrpc import BaseValidator
class TestValidator(BaseValidator):
def validator(self, form, field):
# Custom logic: value must be uppercase
if field.data and not field.data.isupper():
raise ValueError("Field must be uppercase")
```
Use the custom validator in your form:
```python
class TestForm(BaseForm):
action = simple.StringField(
validators=[
StrRangeValidator(allows=["start", "stop"]),
TestValidator()
]
)
```
---
## 4.2 Exception Handling
The framework includes a built-in exception handling system. Just raise exceptions, and the framework will format them into standard JSON-RPC error responses.
### ✅ Example
```python
from simplejrpc.exceptions import RPCException
@app.route(name="hello", form=TestForm)
async def hello(lang, action):
raise RPCException("Test error") # Automatically caught and formatted
```
### ✅ Custom Exception Classes
The framework provides a base exception class that can be extended:
```python
class UnauthorizedError(RPCException):
"""Unauthorized"""
class ValidationError(RPCException):
"""Validation failed"""
class FileNotFoundError(RPCException):
"""File not found"""
class ValueError(RPCException):
"""Value error"""
class RuntimeError(RPCException):
"""Runtime error"""
```
---
## 4.3 Internationalization (i18n)
The SDK supports multilingual output using `.ini` files, driven by the `lang` parameter in each request.
### ✅ Initialize Language Configuration
Your project root should include an `i18n/` directory:
```bash
project/
├── main.py
└── i18n/
├── zh-CN.ini
└── en.ini
```
Initialize with `GI18n()`:
```python
GI18n(i18n_dir="i18n", lang="zh-CN")
```
> ⚠️ Each request should include a `lang` parameter, which the framework uses to set the language.
---
### ✅ Example 1: Basic Translation
**en.ini**
```ini
TEST_I18N = "test"
```
**Python usage:**
```python
from simplejrpc import i18n
print(i18n.translate("TEST_I18N")) # Output: test
```
---
### ✅ Example 2: Placeholder Translation (Parameterized)
**en.ini**
```ini
TEST_I18N = "test{}"
```
**Python usage:**
```python
from simplejrpc import i18n
print(i18n.translate_ctx("TEST_I18N", "i18n")) # Output: testi18n
```
---
### ✅ Supported Languages
| Language Code | Description | Region/Note |
| ------------- | ------------------- | ---------------- |
| `en` | English | Default |
| `zh-CN` | Simplified Chinese | Mainland China |
| `zh-TW` | Traditional Chinese | Taiwan/Hong Kong |
| `ja` | Japanese | Japan |
| `ru` | Russian | Russia |
---
## 4.4 Middleware Support
The framework supports middleware for handling common logic before and after request processing, such as logging, authentication, or performance analysis.
### ✅ Example Usage
```python
from simplejrpc import ServerApplication
from simplejrpc.interfaces import RPCMiddleware
class CustomMiddleware(RPCMiddleware):
def process_request(self, request, context):
print("[Before] Incoming request:", request)
return request
def process_response(self, response, context):
print("[After] Outgoing response:", response)
return response
# Register middleware
app = ServerApplication("/xxx/app.sock")
app.middleware(CustomMiddleware())
```
---
Would you like this translated version exported into a PDF or Markdown file?
Feedback
--------
Open a ticket / fork the project on [Gitee](https://gitee.com/gmssh_1/simplerpc.git).
Open a ticket / fork the project on [Github](https://github.com/GMSSH/app-sdk-py.git).
Here is the fully translated version of your documentation from Chinese to English:
---
Raw data
{
"_id": null,
"home_page": "https://github.com/GMSSH/app-sdk-py",
"name": "simplejrpc",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "gm, gm-sdk, simplejrpc, gmssh, jsonrpc, jsonrpcserver, jsonrpcclient",
"author": "Zack",
"author_email": "f1125564921@163.com",
"download_url": "https://files.pythonhosted.org/packages/87/2f/faa78c8896eb27ec6fee5f14b0967eb2cb4def6d1eb64e9231ce780d6a52/simplejrpc-2.2.6.tar.gz",
"platform": null,
"description": "[](https://pypi.python.org/pypi/simplejrpc/)\n[](https://pypi.python.org/pypi/simplejrpc/)\n[](https://pypi.org/project/simplejrpc/)\n\nsimplejrpc\n==========\n\n\n# 1. Getting Started Quickly\n\n### 1.1 Install SDK\n\nInstall the SDK using pip:\n\n```bash\npip3 install simplejrpc\n```\n\n> Once installed, you can import and use the SDK functions in your project.\n\n---\n\n# 2. Service Registration\n\n### 2.1 Register a Socket File\n\nSince the SDK communicates with the backend process via a **Unix Socket file** (based on the JSON-RPC 2.0 protocol), you must explicitly specify the `socket_path` to ensure the service generates a `.sock` file and exposes communication capabilities.\n\n```python\n# main.py\nfrom simplejrpc import ServerApplication\n\n# Specify the Unix Socket file path\nsocket_path = \"/xxx/app.socket\"\n\n# Create the application instance\napp = ServerApplication(socket_path=socket_path)\n```\n\n> \u2705 Tip: Make sure the path is writable and does not conflict with other services.\n\n---\n\n### 2.2 Register a Configuration File (Logging System)\n\nTo enable logging, specify the path to a logger config file during initialization. You can also call `app.setup_logger(config_path)` after the app starts to load the logger config dynamically.\n\n* Supported format: **YAML**\n* If not configured, a simple logger provided by loguru is used by default.\n\n```python\n# main.py\nfrom simplejrpc import ServerApplication\n\nsock_path = \"/xxx/app.sock\"\nconfig_path = \"/xxx/config.yaml\"\n\n# Initialize the app with logger configuration\napp = ServerApplication(socket_path=sock_path, config_path=config_path)\n\n# Alternatively, configure the logger after initialization:\n# app.setup_logger(config_path)\n```\n\n---\n\n### 2.3 Register Methods (Business Routes)\n\nRegistering methods exposes functions as interfaces accessible via JSON-RPC.\n\n#### \u2705 Default Registration (Using Function Name)\n\nIf the method name is not explicitly specified, the system will use the function name by default:\n\n```python\nfrom simplejrpc.response import jsonify\n\n\n@app.route() # Registered as 'hello' by default\nasync def hello():\n return jsonify(data=\"hello\", msg=\"OK\")\n```\n\n#### \u2705 Explicit Registration (Specify Method Name)\n\nYou can also specify a method name using the `name` parameter. It\u2019s recommended to keep it consistent with the function name for maintainability:\n\n```python\nfrom simplejrpc.response import jsonify\n\n\n@app.route(name=\"hello\") # Explicitly set method name\nasync def hello():\n return jsonify(data=\"hello\", msg=\"OK\")\n```\n\n> \u26a0\ufe0f Note: If `name` differs from the function name, it may cause confusion during maintenance or calls. Consistent naming is advised.\n\n---\n\n# 3. Making Requests\n\n---\n\n## 3.1 Request and Response Structure\n\n### \u2705 Supported Parameter Formats\n\nThe framework supports two ways of receiving request parameters:\n\n#### \ud83d\udccc Explicit Parameter Declaration (Recommended)\n\nUse when parameters are fixed and clearly named:\n\n```python\n@app.route(name=\"hello\")\nasync def hello(lang, action):\n # Directly receive request parameters lang and action\n ...\n```\n\n\u2705 Advantage: Clear typing, easier validation and maintenance.\n\n---\n\n#### \ud83d\udccc Dynamic Parameter Handling (\\*args, \\*\\*kwargs)\n\nUse when the number of parameters is variable or needs generic processing:\n\n```python\n@app.route(name=\"hello\")\nasync def hello(*args, **kwargs):\n lang = kwargs.get(\"lang\")\n action = kwargs.get(\"action\")\n ...\n```\n\n---\n\n### \u2705 Standard Response Format\n\nAll responses should be returned using `jsonify`, containing `code`, `data`, and `msg` fields:\n\n```python\nfrom simplejrpc.response import jsonify\n\n\n@app.route(name=\"hello\")\nasync def hello():\n return jsonify(code=400, data=True, msg=\"Operation failed\")\n```\n\n---\n\n### \u2705 Example Response Structure\n\n#### Success Response:\n\n```json\n{\n \"jsonrpc\": \"2.0\",\n \"result\": {\n \"code\": 200,\n \"meta\": {\n \"endpoint\": null,\n \"close\": 1\n },\n \"data\": [],\n \"msg\": \"OK\"\n },\n \"id\": 1\n}\n```\n\n#### Error Response:\n\n```json\n{\n \"jsonrpc\": \"2.0\",\n \"result\": {\n \"code\": 400,\n \"meta\": {\n \"endpoint\": null,\n \"close\": 1\n },\n \"data\": null,\n \"msg\": \"expected value ['start', 'stop']\"\n },\n \"id\": 1\n}\n```\n\n---\n\n## 3.2 Start the Service\n\nExample server code:\n\n```python\n# main.py\nimport asyncio\nfrom simplejrpc import ServerApplication\nfrom simplejrpc.response import jsonify\n\nsocket_path = \"/xxx/app.socket\"\napp = ServerApplication(socket_path)\n\n\n@app.route(name=\"hello\")\nasync def hello():\n return jsonify(data=\"hello\", msg=\"OK\")\n\n\nif __name__ == \"__main__\":\n asyncio.run(app.run())\n```\n\nStart the service:\n\n```bash\n$ python3 main.py\n```\n\n---\n\n## 3.3 Call Interface (Client Test)\n\nUse the SDK's `Request` class for testing:\n\n```python\nfrom simplejrpc import Request\n\n# Must match the socket path used by the server\nsocket_path = \"/xxx/app.sock\"\n\n\ndef test_hello():\n method = \"hello\"\n params = {\n \"lang\": \"zh-CN\",\n \"action\": \"start\"\n }\n\n request = Request(socket_path)\n result = request.send_request(method, params)\n print(\"[recv] >\", result)\n```\n\n---\n\n# 4. Making Requests\n\n---\n\n## 4.1 Form Validation\n\nThe SDK integrates [`wtforms`](https://wtforms.readthedocs.io/en/3.1.x/) to provide a simple yet powerful validation system with support for custom validators.\n\n### \u2705 Example: Define and Use a Form Class\n\n```python\nfrom simplejrpc.schemas import BaseForm, StrRangeValidator, simple\nfrom simplejrpc.response import jsonify\n\n\n# Custom form class, restricts 'action' to \"start\" or \"stop\"\nclass TestForm(BaseForm):\n action = simple.StringField(\n validators=[StrRangeValidator(allows=[\"start\", \"stop\"])]\n )\n\n\n# Specify socket path and register app\nsocket_path = \"/xxx/app.socket\"\napp = ServerApplication(socket_path)\n\n\n# Specify 'form' to trigger validation automatically\n@app.route(name=\"hello\", form=TestForm)\nasync def hello(lang, action):\n return jsonify(data=[1, 2, 3], msg=\"OK\")\n```\n\n---\n\n### \u2705 Custom Validators\n\nYou can create custom validation logic by extending `BaseValidator`.\n\n> A custom validator class must inherit from `BaseValidator` and implement the `validator(form, field)` method. Only two parameters are accepted: the form instance and the field instance.\n\n```python\nfrom simplejrpc import BaseValidator\n\n\nclass TestValidator(BaseValidator):\n def validator(self, form, field):\n # Custom logic: value must be uppercase\n if field.data and not field.data.isupper():\n raise ValueError(\"Field must be uppercase\")\n```\n\nUse the custom validator in your form:\n\n```python\nclass TestForm(BaseForm):\n action = simple.StringField(\n validators=[\n StrRangeValidator(allows=[\"start\", \"stop\"]),\n TestValidator()\n ]\n )\n```\n\n---\n\n## 4.2 Exception Handling\n\nThe framework includes a built-in exception handling system. Just raise exceptions, and the framework will format them into standard JSON-RPC error responses.\n\n### \u2705 Example\n\n```python\nfrom simplejrpc.exceptions import RPCException\n\n\n@app.route(name=\"hello\", form=TestForm)\nasync def hello(lang, action):\n raise RPCException(\"Test error\") # Automatically caught and formatted\n```\n\n### \u2705 Custom Exception Classes\n\nThe framework provides a base exception class that can be extended:\n\n```python\nclass UnauthorizedError(RPCException):\n \"\"\"Unauthorized\"\"\"\n\nclass ValidationError(RPCException):\n \"\"\"Validation failed\"\"\"\n\nclass FileNotFoundError(RPCException):\n \"\"\"File not found\"\"\"\n\nclass ValueError(RPCException):\n \"\"\"Value error\"\"\"\n\nclass RuntimeError(RPCException):\n \"\"\"Runtime error\"\"\"\n```\n\n---\n\n## 4.3 Internationalization (i18n)\n\nThe SDK supports multilingual output using `.ini` files, driven by the `lang` parameter in each request.\n\n### \u2705 Initialize Language Configuration\n\nYour project root should include an `i18n/` directory:\n\n```bash\nproject/\n\u251c\u2500\u2500 main.py\n\u2514\u2500\u2500 i18n/\n \u251c\u2500\u2500 zh-CN.ini\n \u2514\u2500\u2500 en.ini\n```\n\nInitialize with `GI18n()`:\n\n```python\nGI18n(i18n_dir=\"i18n\", lang=\"zh-CN\")\n```\n\n> \u26a0\ufe0f Each request should include a `lang` parameter, which the framework uses to set the language.\n\n---\n\n### \u2705 Example 1: Basic Translation\n\n**en.ini**\n\n```ini\nTEST_I18N = \"test\"\n```\n\n**Python usage:**\n\n```python\nfrom simplejrpc import i18n\n\nprint(i18n.translate(\"TEST_I18N\")) # Output: test\n```\n\n---\n\n### \u2705 Example 2: Placeholder Translation (Parameterized)\n\n**en.ini**\n\n```ini\nTEST_I18N = \"test{}\"\n```\n\n**Python usage:**\n\n```python\nfrom simplejrpc import i18n\n\nprint(i18n.translate_ctx(\"TEST_I18N\", \"i18n\")) # Output: testi18n\n```\n\n---\n\n### \u2705 Supported Languages\n\n| Language Code | Description | Region/Note |\n| ------------- | ------------------- | ---------------- |\n| `en` | English | Default |\n| `zh-CN` | Simplified Chinese | Mainland China |\n| `zh-TW` | Traditional Chinese | Taiwan/Hong Kong |\n| `ja` | Japanese | Japan |\n| `ru` | Russian | Russia |\n\n---\n\n## 4.4 Middleware Support\n\nThe framework supports middleware for handling common logic before and after request processing, such as logging, authentication, or performance analysis.\n\n### \u2705 Example Usage\n\n```python\nfrom simplejrpc import ServerApplication\nfrom simplejrpc.interfaces import RPCMiddleware\n\n\nclass CustomMiddleware(RPCMiddleware):\n def process_request(self, request, context):\n print(\"[Before] Incoming request:\", request)\n return request\n\n def process_response(self, response, context):\n print(\"[After] Outgoing response:\", response)\n return response\n\n\n# Register middleware\napp = ServerApplication(\"/xxx/app.sock\")\napp.middleware(CustomMiddleware())\n```\n\n---\n\nWould you like this translated version exported into a PDF or Markdown file?\n\n\nFeedback\n--------\n\nOpen a ticket / fork the project on [Gitee](https://gitee.com/gmssh_1/simplerpc.git).\n\nOpen a ticket / fork the project on [Github](https://github.com/GMSSH/app-sdk-py.git).\n\nHere is the fully translated version of your documentation from Chinese to English:\n\n---\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "simple jsonrpc",
"version": "2.2.6",
"project_urls": {
"Homepage": "https://github.com/GMSSH/app-sdk-py"
},
"split_keywords": [
"gm",
" gm-sdk",
" simplejrpc",
" gmssh",
" jsonrpc",
" jsonrpcserver",
" jsonrpcclient"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "b5ca37f967c13dbc9becb76079cda0325f021133b2040253faf441ed02c0adf3",
"md5": "b30e2c2adf1ed98d5217446ac2589007",
"sha256": "bf370f3c822660a0504492aeefda8b87b0b1d80c2746e3a6b66c79f165bd069c"
},
"downloads": -1,
"filename": "simplejrpc-2.2.6-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "b30e2c2adf1ed98d5217446ac2589007",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": ">=3.10",
"size": 54474,
"upload_time": "2025-07-14T06:35:31",
"upload_time_iso_8601": "2025-07-14T06:35:31.249604Z",
"url": "https://files.pythonhosted.org/packages/b5/ca/37f967c13dbc9becb76079cda0325f021133b2040253faf441ed02c0adf3/simplejrpc-2.2.6-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "872ffaa78c8896eb27ec6fee5f14b0967eb2cb4def6d1eb64e9231ce780d6a52",
"md5": "7e767adfc6136ae961ac1c1b0971e138",
"sha256": "4a74f0f45641fe97fed19f10322f3dcba91b94bb192dbddbf97769e7cb361426"
},
"downloads": -1,
"filename": "simplejrpc-2.2.6.tar.gz",
"has_sig": false,
"md5_digest": "7e767adfc6136ae961ac1c1b0971e138",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 53616,
"upload_time": "2025-07-14T06:35:32",
"upload_time_iso_8601": "2025-07-14T06:35:32.752789Z",
"url": "https://files.pythonhosted.org/packages/87/2f/faa78c8896eb27ec6fee5f14b0967eb2cb4def6d1eb64e9231ce780d6a52/simplejrpc-2.2.6.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-14 06:35:32",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "GMSSH",
"github_project": "app-sdk-py",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "jsonrpcclient",
"specs": [
[
"==",
"4.0.3"
]
]
},
{
"name": "jsonrpcserver",
"specs": [
[
"==",
"5.0.9"
]
]
},
{
"name": "loguru",
"specs": [
[
"==",
"0.7.3"
]
]
},
{
"name": "PyYAML",
"specs": [
[
"==",
"6.0.2"
]
]
},
{
"name": "WTForms",
"specs": [
[
"==",
"3.2.1"
]
]
}
],
"lcname": "simplejrpc"
}