The MSGPACK-RPC protocol
Example
The following example shows how to use the
MSGPACKRPCProtocol
class in a custom
application, without using any other components:
Server
from tinyrpc.protocols.msgpackrpc import MSGPACKRPCProtocol
from tinyrpc import BadRequestError, RPCRequest
rpc = MSGPACKRPCProtocol()
# the code below is valid for all protocols, not just MSGPACKRPCProtocol,
# as long as you don't need to handle batch RPC requests:
def handle_incoming_message(self, data):
try:
request = rpc.parse_request(data)
except BadRequestError as e:
# request was invalid, directly create response
response = e.error_respond(e)
else:
# we got a valid request
# the handle_request function is user-defined
# and returns some form of response
response = handle_request(request)
# now send the response to the client
if response != None:
send_to_client(response.serialize())
def handle_request(request):
try:
# do magic with method, args, kwargs...
return request.respond(result)
except Exception as e:
# for example, a method wasn't found
return request.error_respond(e)
Client
from tinyrpc.protocols.msgpackrpc import MSGPACKRPCProtocol
rpc = MSGPACKRPCProtocol()
# again, code below is protocol-independent
# assuming you want to call method(*args, **kwargs)
request = rpc.create_request(method, args, kwargs)
reply = send_to_server_and_get_reply(request)
response = rpc.parse_reply(reply)
if hasattr(response, 'error'):
# error handling...
else:
# the return value is found in response.result
do_something_with(response.result)
Finally, one-way requests are requests where the client does not expect an answer:
request = rpc.create_request(method, args, kwargs, one_way=True)
send_to_server(request)
# done
Protocol implementation
API Reference
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCProtocol(id_generator: Generator[object, None, None] | None = None, *args, **kwargs)
Bases:
RPCProtocol
MSGPACKRPC protocol implementation.
- request_factory() MSGPACKRPCRequest
Factory for request objects.
Allows derived classes to use requests derived from
MSGPACKRPCRequest
.- Return type:
- create_request(method: str, args: List[Any] = None, kwargs: Dict[str, Any] = None, one_way: bool = False) MSGPACKRPCRequest
Creates a new
MSGPACKRPCRequest
object.Called by the client when constructing a request. MSGPACK-RPC allows only the
args
argument to be set; keyword arguments are not supported.- Parameters:
method (str) – The method name to invoke.
args (list) – The positional arguments to call the method with.
kwargs (dict) – The keyword arguments to call the method with; must be
None
as the protocol does not support keyword arguments.one_way (bool) – The request is an update, i.e. it does not expect a reply.
- Returns:
A new request instance
- Return type:
- Raises:
InvalidRequestError – when
kwargs
is defined.
- parse_reply(data: bytes) MSGPACKRPCSuccessResponse | MSGPACKRPCErrorResponse
De-serializes and validates a response.
Called by the client to reconstruct the serialized
MSGPACKRPCResponse
.- Parameters:
data (bytes) – The data stream received by the transport layer containing the serialized response.
- Returns:
A reconstructed response.
- Return type:
- Raises:
InvalidReplyError – if the response is not valid MSGPACK or does not conform to the standard.
- parse_request(data: bytes) MSGPACKRPCRequest
De-serializes and validates a request.
Called by the server to reconstruct the serialized
MSGPACKRPCRequest
.- Parameters:
data (bytes) – The data stream received by the transport layer containing the serialized request.
- Returns:
A reconstructed request.
- Return type:
- Raises:
MSGPACKRPCParseError – if the
data
cannot be parsed as valid MSGPACK.MSGPACKRPCInvalidRequestError – if the request does not comply with the standard.
- raise_error(error: MSGPACKRPCErrorResponse | Dict[str, Any]) MSGPACKRPCError
Recreates the exception.
Creates a
MSGPACKRPCError
instance and raises it.This allows the error code and the message of the original exception to propagate into the client code.
The
raises_error
flag controls if the exception object is raised or returned.- Returns:
the exception object if it is not allowed to raise it.
- Raises:
MSGPACKRPCError – when the exception can be raised. The exception object will contain
message
andcode
.
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCRequest
Bases:
RPCRequest
Defines a MSGPACK-RPC request.
- one_way
Request or Notification.
- Type:
bool
This flag indicates if the client expects to receive a reply (request:
one_way = False
) or not (notification:one_way = True
).Note that it is possible for the server to return an error response. For example if the request becomes unreadable and the server is not able to determine that it is in fact a notification an error should be returned. However, once the server had verified that the request is a notification no reply (not even an error) should be returned.
- unique_id
Correlation ID used to match request and response.
- Type:
int
Generated by the client, the server copies it from request to corresponding response.
- method
The name of the RPC function to be called.
- Type:
str
The
method
attribute uses the name of the function as it is known by the public. TheRPCDispatcher
allows the use of public aliases in the@public
decorators. These are the names used in themethod
attribute.
- args
The positional arguments of the method call.
- Type:
list
The contents of this list are the positional parameters for the
method
called. It is eventually called asmethod(*args)
.
- error_respond(error: Exception | str) MSGPACKRPCErrorResponse | None
Create an error response to this request.
When processing the request produces an error condition this method can be used to create the error response object.
- Parameters:
error (Exception or str) – Specifies what error occurred.
- Returns:
An error response object that can be serialized and sent to the client.
- Return type:
;py:class:MSGPACKRPCErrorResponse
- respond(result: Any) MSGPACKRPCSuccessResponse | None
Create a response to this request.
When processing the request completed successfully this method can be used to create a response object.
- Parameters:
result (Anything that can be encoded by MSGPACK.) – The result of the invoked method.
- Returns:
A response object that can be serialized and sent to the client.
- Return type:
- serialize() bytes
Returns a serialization of the request.
Converts the request into a bytes object that can be passed to and by the transport layer.
This is an abstract method that must be overridden in a derived class.
- Returns:
A bytes object to be passed on to a transport.
- Return type:
bytes
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCSuccessResponse
Bases:
RPCResponse
- serialize()
Returns a serialization of the response.
Converts the response into a bytes object that can be passed to and by the transport layer.
This is an abstract method that must be overridden in a derived class.
- Returns:
The serialized encoded response object.
- Return type:
bytes
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCErrorResponse
Bases:
RPCErrorResponse
- serialize()
Returns a serialization of the response.
Converts the response into a bytes object that can be passed to and by the transport layer.
This is an abstract method that must be overridden in a derived class.
- Returns:
The serialized encoded response object.
- Return type:
bytes
Errors and error handling
API Reference
- class tinyrpc.protocols.msgpackrpc.FixedErrorMessageMixin(*args, **kwargs)
Bases:
object
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCParseError(*args, **kwargs)
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCInvalidRequestError(*args, **kwargs)
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCMethodNotFoundError(*args, **kwargs)
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCInvalidParamsError(*args, **kwargs)
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCInternalError(*args, **kwargs)
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCServerError(*args, **kwargs)
- class tinyrpc.protocols.msgpackrpc.MSGPACKRPCError(error: MSGPACKRPCErrorResponse | Tuple[int, str])
Bases:
FixedErrorMessageMixin
,RPCError
Reconstructs (to some extend) the server-side exception.
The client creates this exception by providing it with the
error
attribute of the MSGPACK error response object returned by the server.- Parameters:
error – This tuple contains the error specification: the numeric error code and the error description.
Adding custom exceptions
Note
Unlike JSON-RPC, the MSGPACK-RPC specification does not specify how
the error messages should look like; the protocol allows any arbitrary
MSGPACK object as an error object. For sake of compatibility with JSON-RPC,
this implementation uses MSGPACK lists of length 2 (consisting of a numeric
error code and an error description) to represent errors in the serialized
representation. These are transparently decoded into
MSGPACKRPCError
instances as
needed. The error codes for parsing errors, invalid requests, unknown RPC
methods and so on match those from the JSON-RPC specification.
To add custom errors you need to combine an Exception
subclass
with the FixedErrorMessageMixin
class
to create your exception object which you can raise.
So a version of the reverse string example that dislikes palindromes could look like:
from tinyrpc.protocols.msgpackrpc import FixedErrorMessageMixin, MSGPACKRPCProtocol
from tinyrpc.dispatch import RPCDispatcher
dispatcher = RPCDispatcher()
class PalindromeError(FixedErrorMessageMixin, Exception):
msgpackrpc_error_code = 99
message = "Ah, that's cheating!"
@dispatcher.public
def reverse_string(s):
r = s[::-1]
if r == s:
raise PalindromeError()
return r