JSON-RPC implementation for Django's channels library.
Project description
channels-rpc
channels-rpc enables JSON-RPC 2.0 functionality on top of Django Channels WebSockets with strict protocol compliance, type safety, and production-ready features.
Features
- ✅ Strict JSON-RPC 2.0 compliance - Fully implements the JSON-RPC 2.0 specification
- ✅ Django Channels integration - Built on Django Channels for WebSocket support
- ✅ Type safety - Comprehensive type hints with mypy validation (0 type errors)
- ✅ Security - DoS protection with request size limits, no information leakage
- ✅ Performance - Optimized with cached introspection (31x faster method execution)
- ✅ WebSocket only - Focused on real-time bidirectional communication (HTTP removed in 1.0.0)
- ✅ Easy integration - Simple decorator-based API
- ✅ Django settings - Runtime configuration via Django settings (new in 1.0.0)
- ✅ Lifecycle signals - Monitor RPC calls with Django signals (new in 1.0.0)
- ✅ Middleware support - Extensible middleware pipeline for cross-cutting concerns (new in 1.0.0)
- ✅ Custom serialization - Support for custom JSON encoders (new in 1.0.0)
- ✅ Permission control - Decorator-based authorization with Django permissions (new in 1.0.0)
- ✅ API introspection - Discover methods, signatures, and documentation at runtime (new in 1.0.0)
- ✅ Well tested - 363 tests with 88% coverage
JSON-RPC 2.0 Compliance
channels-rpc implements the JSON-RPC 2.0 specification with strict protocol adherence.
Supported Features
Version Checking
- Only
"jsonrpc": "2.0"is accepted - Other versions are rejected with
INVALID_REQUESTerror (-32600) - Validation enforced in
channels_rpc/rpc_base.py
Request Format
- Required fields:
jsonrpc(string),method(string) - Optional fields:
params(object or array),id(string, number, or null) - Notification requests: Requests without
idare treated as notifications (no response sent)
// Method call (expects response)
{
"jsonrpc": "2.0",
"method": "subtract",
"params": {"minuend": 42, "subtrahend": 23},
"id": 1
}
// Notification (no response)
{
"jsonrpc": "2.0",
"method": "notify",
"params": {"message": "hello"}
}
Response Format
- Success response: Contains
resultfield - Error response: Contains
errorobject withcode(integer),message(string), and optionaldatafield - All responses include
jsonrpc: "2.0"andidmatching the request
// Success
{"jsonrpc": "2.0", "result": 19, "id": 1}
// Error
{
"jsonrpc": "2.0",
"error": {
"code": -32601,
"message": "Method Not Found: 'nonexistent'",
"data": {"method": "nonexistent"}
},
"id": 1
}
Parameter Formats
- Named parameters (object):
"params": {"name": "value"} - Positional parameters (array):
"params": [1, 2, 3] - Empty/omitted: Both
"params": {}and omitted params field are valid
Error Codes
Standard JSON-RPC 2.0 error codes (defined in channels_rpc/exceptions.py):
| Code | Constant | Meaning |
|---|---|---|
| -32700 | PARSE_ERROR |
Invalid JSON received |
| -32600 | INVALID_REQUEST |
JSON is not a valid Request object |
| -32601 | METHOD_NOT_FOUND |
Method does not exist |
| -32602 | INVALID_PARAMS |
Invalid method parameters |
| -32603 | INTERNAL_ERROR |
Internal JSON-RPC error |
Server-defined error codes (-32099 to -32000):
| Code | Constant | Meaning |
|---|---|---|
| -32000 | GENERIC_APPLICATION_ERROR |
Generic application error (deprecated, use specific codes) |
| -32001 | REQUEST_TOO_LARGE |
Request exceeds size limits |
| -32701 | PARSE_RESULT_ERROR |
Error serializing result |
Request Size Limits
To prevent denial-of-service attacks, the following limits are enforced (see channels_rpc/limits.py):
- MAX_MESSAGE_SIZE: 10MB per message
- MAX_ARRAY_LENGTH: 10,000 items in params array
- MAX_STRING_LENGTH: 1MB per string parameter
- MAX_NESTING_DEPTH: 20 levels of nested objects/arrays
- MAX_METHOD_NAME_LENGTH: 256 characters
Requests exceeding these limits return REQUEST_TOO_LARGE error (-32001).
NOT Supported
Batch Requests
Batch requests (arrays of multiple JSON-RPC requests) are intentionally not supported. Each WebSocket message must contain a single JSON-RPC request or notification.
// NOT SUPPORTED - will be rejected
[
{"jsonrpc": "2.0", "method": "sum", "params": [1, 2], "id": 1},
{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 2}
]
To execute multiple methods, send separate WebSocket messages for each request.
Installation
$ pip install git+ssh://git@github.com/quantivly/channels-rpc.git
Use
It is intended to be used as a WebSocket consumer. Use the async consumer AsyncJsonRpcWebsocketConsumer:
from channels_rpc import AsyncJsonRpcWebsocketConsumer
class MyJsonRpcConsumer(AsyncJsonRpcWebsocketConsumer):
async def connect(self):
"""Perform things on WebSocket connection start"""
await self.accept()
print("connect")
# Do stuff if needed
async def disconnect(self, code):
"""Perform things on WebSocket connection close"""
print("disconnect")
# Do stuff if needed
AsyncJsonRpcWebsocketConsumer derives from channels
AsyncJsonWebsocketConsumer.
Then, the last step is to create the RPC method hooks using the rpc_method
decorator:
@MyJsonRpcConsumer.rpc_method()
async def ping():
return "pong"
Or, with a custom name:
@MyJsonRpcConsumer.rpc_method("mymodule.rpc.ping")
async def ping():
return "pong"
Will now be callable with "method":"mymodule.rpc.ping" in the rpc call:
{
"id":1,
"jsonrpc":"2.0",
"method":"mymodule.rpc.ping",
"params":{}
}
RPC methods can obviously accept parameters. They also return "results" or "errors":
@MyJsonRpcConsumer.rpc_method("mymodule.rpc.ping")
async def ping(fake_an_error):
if fake_an_error:
# Will return an error to the client
# --> {"id":1, "jsonrpc":"2.0","method":"mymodule.rpc.ping","params":{}} # <-- {"id": 1, "jsonrpc": "2.0", "error": {"message": "fake_error", "code": -32000, "data": ["fake_error"]}} raise Exception("fake_error")
else:
# Will return a result to the client
# --> {"id":1, "jsonrpc":"2.0","method":"mymodule.rpc.ping","params":{}} # <-- {"id": 1, "jsonrpc": "2.0", "result": "pong"} return "pong"
Accessing Consumer and Request Context
RPC methods can access the consumer instance, request metadata, and Django Channels scope through the RpcContext parameter. When a method's first parameter (after self for bound methods) is typed as RpcContext, it will be automatically injected during execution.
from channels_rpc import RpcContext
@MyJsonRpcConsumer.rpc_method()
async def json_rpc_method(ctx: RpcContext, param1: str):
# Access the consumer instance
consumer = ctx.consumer
# Access Django Channels scope (sessions, user, etc.)
session = ctx.scope.get("session", {})
# Access request metadata
method_name = ctx.method_name # "json_rpc_method"
rpc_id = ctx.rpc_id # Request ID from JSON-RPC call
is_notification = ctx.is_notification # False for methods, True for notifications
# Do something with the context
return f"Hello {param1}"
Complete Example:
from channels_rpc import AsyncJsonRpcWebsocketConsumer, RpcContext
class MyJsonRpcConsumer(AsyncJsonRpcWebsocketConsumer):
pass
@MyJsonRpcConsumer.rpc_method()
async def ping(ctx: RpcContext):
# Access session through context
ctx.scope["session"]["test"] = True
# Log the request
print(f"Ping called with ID {ctx.rpc_id}")
return "pong"
@MyJsonRpcConsumer.rpc_method()
async def get_user_info(ctx: RpcContext):
# Access authenticated user from scope
user = ctx.scope.get("user")
if user and user.is_authenticated:
return {
"username": user.username,
"email": user.email
}
return {"error": "Not authenticated"}
Available Context Attributes:
ctx.consumer: The consumer instance handling the RPC requestctx.method_name: Name of the RPC method being calledctx.rpc_id: Request ID from the JSON-RPC call (None for notifications)ctx.is_notification: Whether this is a notification (no response expected)ctx.scope: Django Channels scope dict containing:client: (host, port) tupleheaders: Request headerscookies: Request cookiessession: Django session (if http_user enabled)user: Authenticated user (if http_user enabled)
Testing
The JsonRpcConsumer class can be tested the same way Channels Consumers are tested. See here
Logging Configuration
channels-rpc uses Python's logging module with the logger name "channels_rpc". Configure it in your Django settings:
# settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {message}',
'style': '{',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'channels_rpc': {
'handlers': ['console'],
'level': 'INFO', # Use 'DEBUG' for detailed RPC call logging
'propagate': False,
},
},
}
Log Levels:
DEBUG- Detailed RPC method execution, parameter loggingINFO- Connection events, application errorsWARNING- Invalid requests, unexpected dataERROR- Internal errors (should not occur in production)
Security Features
Request Size Limits (DoS Protection)
channels-rpc enforces size limits to prevent denial-of-service attacks:
- MAX_MESSAGE_SIZE: 10MB per message
- MAX_ARRAY_LENGTH: 10,000 items in params array
- MAX_STRING_LENGTH: 1MB per string parameter
- MAX_NESTING_DEPTH: 20 levels of nested objects
- MAX_METHOD_NAME_LENGTH: 256 characters
These limits are enforced automatically. Oversized requests return a JsonRpcErrorCode.REQUEST_TOO_LARGE error.
Error Response Sanitization
Error responses never leak internal details:
- Generic exceptions return sanitized messages
- Stack traces are logged but not sent to clients
- Parameter validation errors include only safe context
Scope Validation
Call self.validate_scope() in your connect() method to validate WebSocket connection metadata:
from channels_rpc import AsyncJsonRpcWebsocketConsumer
class MyJsonRpcConsumer(AsyncJsonRpcWebsocketConsumer):
async def connect(self):
self.validate_scope() # Validates scope structure
await self.accept()
Error Handling
channels-rpc uses an IntEnum for error codes:
from channels_rpc import JsonRpcErrorCode, JsonRpcError
# Standard JSON-RPC 2.0 error codes
JsonRpcErrorCode.PARSE_ERROR # -32700
JsonRpcErrorCode.INVALID_REQUEST # -32600
JsonRpcErrorCode.METHOD_NOT_FOUND # -32601
JsonRpcErrorCode.INVALID_PARAMS # -32602
JsonRpcErrorCode.INTERNAL_ERROR # -32603
# Server-defined error codes
JsonRpcErrorCode.GENERIC_APPLICATION_ERROR # -32000
JsonRpcErrorCode.REQUEST_TOO_LARGE # -32001
JsonRpcErrorCode.PARSE_RESULT_ERROR # -32701
Raise JsonRpcError in your RPC methods for controlled error responses:
from channels_rpc import JsonRpcError, JsonRpcErrorCode
@MyConsumer.rpc_method()
def my_method(value):
if value < 0:
raise JsonRpcError(
rpc_id=None, # Will be filled automatically
code=JsonRpcErrorCode.INVALID_PARAMS,
data={"field": "value", "constraint": "must be non-negative"}
)
return value * 2
Error Code Usage Guide
Choose the appropriate error code to help clients handle errors correctly:
Standard Protocol Errors - Automatically generated:
PARSE_ERROR- Automatically raised by framework for invalid JSONINVALID_REQUEST- Automatically raised for malformed JSON-RPC requestsMETHOD_NOT_FOUND- Automatically raised when method doesn't existINVALID_PARAMS- Use for parameter validation failuresINTERNAL_ERROR- Internal server errors
Application Errors:
GENERIC_APPLICATION_ERROR- Generic application-level errors (deprecated, prefer specific custom codes)REQUEST_TOO_LARGE- Automatically raised when size limits exceededPARSE_RESULT_ERROR- Result serialization failures
Best Practices:
- Use standard codes when appropriate - The JSON-RPC 2.0 spec codes cover most common scenarios
- Include data field - Provide context about what went wrong
- Don't leak secrets - Never include passwords, tokens, or internal paths in error data
- Be consistent - Use the same error codes for similar failures across your API
Example:
from channels_rpc import JsonRpcError, JsonRpcErrorCode, RpcContext
@MyConsumer.rpc_method()
async def update_user(ctx: RpcContext, user_id: int, email: str):
# Input validation failure
if not validate_email(email):
raise JsonRpcError(
ctx.rpc_id,
JsonRpcErrorCode.INVALID_PARAMS,
data={"field": "email", "error": "Invalid format"}
)
# Application-level error
try:
user = await User.objects.aget(id=user_id)
except User.DoesNotExist:
raise JsonRpcError(
ctx.rpc_id,
JsonRpcErrorCode.GENERIC_APPLICATION_ERROR,
data={"resource": "user", "id": user_id}
)
user.email = email
await user.asave()
return {"success": True}
Configuration
Configure channels-rpc via Django settings under the CHANNELS_RPC key:
# settings.py
CHANNELS_RPC = {
# Size limits for DoS protection (all optional, defaults shown)
'MAX_MESSAGE_SIZE': 10 * 1024 * 1024, # 10MB
'MAX_ARRAY_LENGTH': 10000,
'MAX_STRING_LENGTH': 1024 * 1024, # 1MB
'MAX_NESTING_DEPTH': 20,
'MAX_METHOD_NAME_LENGTH': 256,
# Logging configuration
'LOG_RPC_PARAMS': False, # Set True only in development (may expose PII)
'SANITIZE_ERRORS': True, # Always sanitize errors in responses
}
Access configuration programmatically:
from channels_rpc.config import get_config
config = get_config()
print(config.limits.max_message_size) # 10485760
Middleware
Middleware provides a way to add cross-cutting concerns to RPC request/response handling:
from channels_rpc import AsyncJsonRpcWebsocketConsumer
class LoggingMiddleware:
def process_request(self, data, consumer):
print(f"RPC call: {data.get('method')}")
return data
def process_response(self, response, consumer):
print(f"RPC response: {response.get('id')}")
return response
class MyConsumer(AsyncJsonRpcWebsocketConsumer):
# Middleware applied in order
middleware = [
LoggingMiddleware(),
# Add more middleware...
]
Built-in Middleware (in channels_rpc.middleware):
LoggingMiddleware- Example middleware that logs RPC calls with timing
Middleware Patterns (see examples/comprehensive_example.py):
- Custom middleware implementation
- Request/response processing
- Authentication and logging patterns
Signals
Monitor RPC lifecycle with Django signals:
from channels_rpc.signals import rpc_method_started, rpc_method_completed, rpc_method_failed
import logging
logger = logging.getLogger(__name__)
def log_rpc_call(sender, method_name, duration, **kwargs):
logger.info(f"RPC {method_name} completed in {duration:.3f}s")
def alert_on_error(sender, method_name, error, **kwargs):
logger.error(f"RPC {method_name} failed: {error}")
rpc_method_completed.connect(log_rpc_call)
rpc_method_failed.connect(alert_on_error)
Available signals:
rpc_method_started- Method execution startsrpc_method_completed- Method completes successfullyrpc_method_failed- Method raises errorrpc_client_connected- WebSocket client connectsrpc_client_disconnected- WebSocket client disconnects
Permission-Based Access Control
Restrict RPC methods with Django permissions:
from channels_rpc import AsyncJsonRpcWebsocketConsumer, RpcContext
from channels_rpc.decorators import permission_required
class MyConsumer(AsyncJsonRpcWebsocketConsumer):
pass
@MyConsumer.rpc_method()
@permission_required('myapp.can_delete_users')
async def delete_user(ctx: RpcContext, user_id: int):
# Only users with permission can call this
User.objects.get(id=user_id).delete()
return {'deleted': True}
@MyConsumer.rpc_method()
@permission_required('myapp.view_reports', 'myapp.export_data')
async def export_report(ctx: RpcContext, report_id: int):
# User must have BOTH permissions
return generate_report(report_id)
Security Note: Unauthorized calls return METHOD_NOT_FOUND (not auth error) to prevent method enumeration.
Custom JSON Encoder
Serialize custom types (datetime, Decimal, dataclasses):
import json
from datetime import datetime
from decimal import Decimal
from channels_rpc import AsyncJsonRpcWebsocketConsumer
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Decimal):
return float(obj)
return super().default(obj)
class MyConsumer(AsyncJsonRpcWebsocketConsumer):
json_encoder_class = CustomEncoder
@MyConsumer.rpc_method()
async def get_data():
return {
'timestamp': datetime.now(), # Serialized as ISO string
'amount': Decimal('123.45'), # Serialized as float
}
API Introspection
Discover available methods and generate documentation:
# List all methods
methods = MyConsumer.get_rpc_methods()
# ['add', 'subtract', 'get_user']
# Get detailed method info
info = MyConsumer.get_method_info('get_user')
# MethodInfo(
# name='get_user',
# signature='(ctx: RpcContext, user_id: int) -> dict',
# docstring='Get user by ID...',
# accepts_context=True,
# transport_options={'websocket': True}
# )
# Generate complete API description (OpenRPC-compatible)
api_doc = MyConsumer.describe_api()
# {
# 'methods': [...],
# 'notifications': [...],
# 'consumer_class': 'MyConsumer'
# }
What's New in 1.0.0
New Features
🎯 Django Settings Integration
- Configure size limits, logging, and behavior via
CHANNELS_RPCDjango setting - Runtime configuration without code changes
- See Configuration section
📡 Lifecycle Signals
- Monitor RPC calls with 5 Django signals:
rpc_method_started,rpc_method_completed,rpc_method_failed,rpc_client_connected,rpc_client_disconnected - Integrate with APM tools (DataDog, New Relic, etc.)
- Track performance metrics and errors
- See Signals section
🔌 Middleware Support
- Extensible middleware pipeline for cross-cutting concerns
- Protocol-based middleware system via
RpcMiddlewareprotocol - Example middleware:
LoggingMiddlewarefor call tracking - Middleware patterns in
examples/comprehensive_example.py - See Middleware section
Note: Rate limiting, connection limits, and request tracking are application-level concerns in channels-rpc. The library provides the middleware framework and examples, but implementations are application-specific. For production deployments, see QSpace server's implementation as a reference.
🔧 Custom JSON Encoder
- Support for custom JSON encoders (datetime, Decimal, dataclasses, etc.)
- Set
json_encoder_classattribute on consumer - Automatic fallback to str() for non-serializable objects
🔐 Permission-Based Access Control
@permission_required()decorator for Django permission integration- Automatic authorization checking before method execution
- Security-first design (returns METHOD_NOT_FOUND to prevent enumeration)
🔍 API Introspection
get_method_info(method_name)- Get detailed method metadatadescribe_api()- Generate OpenRPC-compatible API descriptions- Runtime method discovery for documentation generation
📊 Comprehensive Error Handling
- Standard JSON-RPC 2.0 error codes (PARSE_ERROR, INVALID_REQUEST, METHOD_NOT_FOUND, INVALID_PARAMS, INTERNAL_ERROR)
- Server-defined error codes (GENERIC_APPLICATION_ERROR, REQUEST_TOO_LARGE, PARSE_RESULT_ERROR)
- Type-safe
JsonRpcErrorCodeIntEnum
Performance Improvements
- 31x faster method execution - Cached introspection eliminates reflection overhead on every call
- Optimized logging - Lazy evaluation prevents unnecessary string formatting
- Reduced code duplication - Eliminated 150+ lines of duplicate decorator code
- Pre-parse size validation - Prevents DoS attacks by checking size before JSON parsing
Type Safety
- Zero mypy errors - Comprehensive type hints throughout
- Protocol classes - Proper typing for Django Channels mixin methods
- IntEnum error codes - Type-safe error code handling with IDE autocomplete
- RpcContext dataclass - Type-safe context parameter
Security Enhancements
- DoS protection - Pre-parse message size validation
- Sanitized error responses - Never leak internal details to clients
- Specific exception handling - RuntimeError no longer masked (indicates bugs)
- Protocol compliance - Fixed critical JSON-RPC 2.0 violations (null ID handling)
Code Quality
- 363 tests with 88% coverage (+119 new tests)
- Pre-commit hooks with mypy, ruff, black, isort
- Clean public API - Explicit
__all__exports - Eliminated duplication - Shared decorator logic in
decorators.py
Breaking Changes in 1.0.0
1. HTTP Parameter Removed from Decorators
The http parameter has been completely removed from all decorators.
Old:
@MyConsumer.rpc_method(websocket=True, http=False)
def my_method():
...
New:
@MyConsumer.rpc_method(websocket=True)
def my_method():
...
Migration: Remove the http parameter from all decorator calls.
2. Logger Name Changed
The logger name changed from "django.channels.rpc" to "channels_rpc" to follow Django conventions.
Old Django settings:
LOGGING = {
'loggers': {
'django.channels.rpc': { # Old name
'handlers': ['console'],
'level': 'DEBUG',
},
},
}
New Django settings:
LOGGING = {
'loggers': {
'channels_rpc': { # New name
'handlers': ['console'],
'level': 'DEBUG',
},
},
}
3. Null ID Now Requires Response
Fixed JSON-RPC 2.0 compliance: "id": null now correctly requires a response (not treated as notification).
Behavior change:
- Notification: Request WITHOUT
idfield (no response) - Request with null ID: Request WITH
"id": null(must receive response)
This is a protocol fix - the previous behavior was non-compliant.
4. Error Codes Now Use IntEnum
Old:
from channels_rpc import INVALID_REQUEST, METHOD_NOT_FOUND
error = JsonRpcError(rpc_id, INVALID_REQUEST)
New:
from channels_rpc import JsonRpcErrorCode
error = JsonRpcError(rpc_id, JsonRpcErrorCode.INVALID_REQUEST)
5. Consumer Context via RpcContext (Recommended)
While **kwargs still works, the recommended approach is using RpcContext:
Old (still works but deprecated):
@MyConsumer.rpc_method()
async def get_user(**kwargs):
consumer = kwargs.get('consumer')
user = consumer.scope.get('user')
New (recommended):
from channels_rpc import RpcContext
@MyConsumer.rpc_method()
async def get_user(ctx: RpcContext):
user = ctx.scope.get('user')
6. HTTP Transport Removed
The HTTP transport has been removed. This library now focuses exclusively on WebSocket transport.
What was removed:
AsyncRpcHttpConsumerclassRPC_ERROR_TO_HTTP_CODEmapping- Individual error code constant exports
Migration:
- Use
AsyncJsonRpcWebsocketConsumerinstead ofAsyncRpcHttpConsumer - Import
JsonRpcErrorCodeenum instead of individual constants - Update routing to use WebSocket endpoints
7. Exception Handling Changed
RuntimeError is no longer caught as an application error (it indicates bugs).
Impact: RuntimeError exceptions will now be logged as internal errors instead of application errors.
Migration: If your code intentionally raises RuntimeError for application logic, use ValueError or TypeError instead.
Production Deployment
Configuration Checklist
For production deployments, ensure these settings are properly configured:
# settings.py (PRODUCTION)
CHANNELS_RPC = {
# Size limits - adjust based on your use case
'MAX_MESSAGE_SIZE': 10 * 1024 * 1024, # 10MB default
# Security - always enabled in production
'SANITIZE_ERRORS': True, # Never leak stack traces
'LOG_RPC_PARAMS': False, # Never log params (may contain PII)
}
Failure Modes and Graceful Degradation
Scenario: Database Unavailable
- Methods accessing Django ORM will fail
- Use
database_sync_to_asyncfromchannels.dbfor safe database access in async methods - Mitigation: Implement database connection pooling and read replicas
Scenario: Redis (Channel Layer) Unavailable
- WebSocket connections will fail to establish
- Existing connections may experience message delivery delays
- Mitigation: Use Redis Sentinel or Cluster for high availability
Scenario: Middleware Errors
- Request middleware errors: Returns
INTERNAL_ERROR, request rejected - Response middleware errors: Original response sent, error logged
- Mitigation: Test middleware thoroughly, handle exceptions internally
Scenario: Method Execution Timeout
- Async methods: Timeout enforced via
@rpc_method(timeout=60) - Sync methods: No timeout enforcement (limitation)
- Mitigation: Use async consumers for timeout guarantees
Scenario: Message Size Limit Exceeded
- Request rejected with
REQUEST_TOO_LARGEerror - Connection remains open, client can retry with smaller payload
- Mitigation: Implement chunking/pagination at application level
Scenario: Rate Limit Exceeded (Application-Level)
- Implementation-specific (see QSpace server for reference)
- Generally: Request rejected with custom application error
- Mitigation: Implement exponential backoff in clients
Security Best Practices
- Always set
SANITIZE_ERRORS: Truein production - Prevents information disclosure - Never set
LOG_RPC_PARAMS: Truein production - May log PII/credentials - Validate all inputs - Use
INVALID_PARAMSfor invalid data - Implement connection limits - Prevent resource exhaustion (see QSpace example)
- Use HTTPS/WSS - Never expose WebSocket endpoints over unencrypted connections
- Implement authentication - Use middleware or
@permission_requireddecorator - Monitor error rates - Use signals to track
rpc_method_failedevents
Performance Recommendations
- Use async consumers - Better concurrency and timeout support
- Cache method introspection - Already done automatically (31x speedup)
- Implement connection pooling - For database connections in async methods
- Monitor promise cleanup - Track periodic cleanup in logs
- Set appropriate size limits - Balance security vs functionality
Why These Changes
These changes improve protocol compliance, type safety, maintainability, and align with Django best practices. The library is now production-ready for high-scale deployments while eliminating technical debt.
Project details
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 channels_rpc-1.0.0.tar.gz.
File metadata
- Download URL: channels_rpc-1.0.0.tar.gz
- Upload date:
- Size: 49.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.10.6 Linux/6.5.0-1024-aws
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0266507e02c39f29eaaa6ab5a8280600f33b6de3c6847422b558b862a56c7efe
|
|
| MD5 |
ecb339f0fe937cce060952c1a5c6f060
|
|
| BLAKE2b-256 |
5da456a93b4fcc55d0f4a2c69c21b1e3207edf1fa6fc1c8f2d8bdf3e997c5027
|
File details
Details for the file channels_rpc-1.0.0-py3-none-any.whl.
File metadata
- Download URL: channels_rpc-1.0.0-py3-none-any.whl
- Upload date:
- Size: 50.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.10.6 Linux/6.5.0-1024-aws
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e0aae2dded0f765c5d18cae47b50a66b085d7ac1488d8f77bd3b2dda8f184dc
|
|
| MD5 |
9834647bcfdd9783bf50c0d3bb7431e4
|
|
| BLAKE2b-256 |
3c4931d13f08504a2ad61e33afb0072f1de090abe749b6b47831ce39eba2f894
|