6. Groups
What You'll Learn
- Organize methods with prefixes
- Create hierarchical method namespaces
- Implement middleware with custom MethodGroups
Basic Group Registration
basic_groups.py
from dataclasses import dataclass
from jsonrpc import JSONRPC, MethodGroup, Method
# Math methods
@dataclass
class BinaryOpParams:
a: float
b: float
class Add(Method):
def execute(self, params: BinaryOpParams) -> float:
return params.a + params.b
class Multiply(Method):
def execute(self, params: BinaryOpParams) -> float:
return params.a * params.b
# String methods
@dataclass
class StringParams:
text: str
class Uppercase(Method):
def execute(self, params: StringParams) -> str:
return params.text.upper()
class Reverse(Method):
def execute(self, params: StringParams) -> str:
return params.text[::-1]
# Setup
rpc = JSONRPC(version='2.0')
math_group = MethodGroup()
math_group.register('add', Add())
math_group.register('multiply', Multiply())
rpc.register('math', math_group)
string_group = MethodGroup()
string_group.register('upper', Uppercase())
string_group.register('reverse', Reverse())
rpc.register('string', string_group)
Request:
Response:
string_request.json
{
"jsonrpc": "2.0",
"method": "string.reverse",
"params": {"text": "hello"},
"id": 2
}
Response:
Hierarchical Namespaces
hierarchical.py
from dataclasses import dataclass
from jsonrpc import JSONRPC, MethodGroup, Method
@dataclass
class UserIdParams:
user_id: int
@dataclass
class DeletedResult:
deleted: int
@dataclass
class UserSummary:
id: int
@dataclass
class ProfileResult:
user_id: int
name: str
# Admin group
class DeleteUser(Method):
def execute(self, params: UserIdParams) -> DeletedResult:
return DeletedResult(deleted=params.user_id)
class ListUsers(Method):
def execute(self, params: None) -> list[UserSummary]:
return [UserSummary(id=1), UserSummary(id=2)]
# Public group
class GetProfile(Method):
def execute(self, params: UserIdParams) -> ProfileResult:
return ProfileResult(user_id=params.user_id, name="John")
# Setup hierarchical structure
rpc = JSONRPC(version='2.0')
# admin.user.*
admin_user_group = MethodGroup()
admin_user_group.register('delete', DeleteUser())
admin_user_group.register('list', ListUsers())
admin_group = MethodGroup()
admin_group.register('user', admin_user_group)
# public.user.*
public_user_group = MethodGroup()
public_user_group.register('profile', GetProfile())
public_group = MethodGroup()
public_group.register('user', public_user_group)
rpc.register('admin', admin_group)
rpc.register('public', public_group)
Methods available:
- admin.user.delete
- admin.user.list
- public.user.profile
Request:
hierarchical_request.json
{
"jsonrpc": "2.0",
"method": "admin.user.delete",
"params": {"user_id": 42},
"id": 1
}
Middleware
MethodGroup is the extension point for cross-cutting concerns. Override execute_method() to inject behavior before and after every method call in the group — logging, caching, rate limiting, authentication guards, and more.
Groups compose cleanly: wrap one group inside another to layer behaviors without touching method logic.
→ Middleware - Reference implementations: logging, caching, rate limiting, auth guards
Key Points
- MethodGroup: Organizes methods with prefix
- Hierarchical: Groups can contain groups (unlimited depth)
- Middleware: Override
execute_method()for custom behavior - Composition: Combine multiple groups for layered functionality
- Separation: Business logic (Method) vs routing (MethodGroup)
Real-World Usage
Use groups for:
- API versioning: v1.*, v2.*
- Access control: public.*, admin.*
- Feature separation: users.*, orders.*, payments.*
What's Next?
→ OpenAPI — Auto-generate API documentation