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(*args, **kwargs)

Bases: tinyrpc.protocols.RPCProtocol

MSGPACKRPC protocol implementation.

request_factory() → tinyrpc.protocols.msgpackrpc.MSGPACKRPCRequest

Factory for request objects.

Allows derived classes to use requests derived from MSGPACKRPCRequest.

Return type:MSGPACKRPCRequest
create_request(method: str, args: List[Any] = None, kwargs: Dict[str, Any] = None, one_way: bool = False) → tinyrpc.protocols.msgpackrpc.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:

MSGPACKRPCRequest

Raises:

InvalidRequestError – when kwargs is defined.

parse_reply(data: bytes) → Union[tinyrpc.protocols.msgpackrpc.MSGPACKRPCSuccessResponse, tinyrpc.protocols.msgpackrpc.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:MSGPACKRPCSuccessResponse or MSGPACKRPCErrorResponse
Raises:InvalidReplyError – if the response is not valid MSGPACK or does not conform to the standard.
parse_request(data: bytes) → tinyrpc.protocols.msgpackrpc.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:

MSGPACKRPCRequest

Raises:
raise_error(error: Union[MSGPACKRPCErrorResponse, Dict[str, Any]]) → tinyrpc.protocols.msgpackrpc.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 and code.
class tinyrpc.protocols.msgpackrpc.MSGPACKRPCRequest

Bases: tinyrpc.protocols.RPCRequest

Defines a MSGPACK-RPC request.

one_way = None

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 = None

Correlation ID used to match request and response.

Type:int

Generated by the client, the server copies it from request to corresponding response.

method = None

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. The RPCDispatcher allows the use of public aliases in the @public decorators. These are the names used in the method attribute.

args = None

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 as method(*args).

error_respond(error: Union[Exception, str]) → Optional[tinyrpc.protocols.msgpackrpc.MSGPACKRPCErrorResponse]

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) → Optional[tinyrpc.protocols.msgpackrpc.MSGPACKRPCSuccessResponse]

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:MSGPACKRPCSuccessResponse
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: tinyrpc.protocols.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: tinyrpc.protocols.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)

Bases: tinyrpc.protocols.msgpackrpc.FixedErrorMessageMixin, tinyrpc.exc.InvalidRequestError

class tinyrpc.protocols.msgpackrpc.MSGPACKRPCInvalidRequestError(*args, **kwargs)

Bases: tinyrpc.protocols.msgpackrpc.FixedErrorMessageMixin, tinyrpc.exc.InvalidRequestError

class tinyrpc.protocols.msgpackrpc.MSGPACKRPCMethodNotFoundError(*args, **kwargs)

Bases: tinyrpc.protocols.msgpackrpc.FixedErrorMessageMixin, tinyrpc.exc.MethodNotFoundError

class tinyrpc.protocols.msgpackrpc.MSGPACKRPCInvalidParamsError(*args, **kwargs)

Bases: tinyrpc.protocols.msgpackrpc.FixedErrorMessageMixin, tinyrpc.exc.InvalidRequestError

class tinyrpc.protocols.msgpackrpc.MSGPACKRPCInternalError(*args, **kwargs)

Bases: tinyrpc.protocols.msgpackrpc.FixedErrorMessageMixin, tinyrpc.exc.InvalidRequestError

class tinyrpc.protocols.msgpackrpc.MSGPACKRPCServerError(*args, **kwargs)

Bases: tinyrpc.protocols.msgpackrpc.FixedErrorMessageMixin, tinyrpc.exc.InvalidRequestError

class tinyrpc.protocols.msgpackrpc.MSGPACKRPCError(error: Union[MSGPACKRPCErrorResponse, Tuple[int, str]])

Bases: tinyrpc.protocols.msgpackrpc.FixedErrorMessageMixin, tinyrpc.exc.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