Custom Serialization

Dubbo Python Custom Serialization

See the full example here

Python is a dynamic language, and its flexibility makes it challenging to design a universal serialization layer as seen in other languages. Therefore, we have removed the “serialization layer” and left it to the users to implement (since users know the formats of the data they will pass).

Serialization typically consists of two parts: serialization and deserialization. We have defined the types for these functions, and custom serialization/deserialization functions must adhere to these “formats.”

First, for serialization functions, we specify:

  1. # A function that takes an argument of any type and returns data of type bytes
  2. SerializingFunction = Callable[[Any], bytes]

Next, for deserialization functions, we specify:

  1. # A function that takes an argument of type bytes and returns data of any type
  2. DeserializingFunction = Callable[[bytes], Any]

Below, I’ll demonstrate how to use custom functions with protobuf and json.

protobuf

  1. For defining and compiling protobuf files, please refer to the protobuf tutorial for detailed instructions.

  2. Set xxx_serializer and xxx_deserializer in the client and server.

    client

    ``` class GreeterServiceStub:

    1. def __init__(self, client: dubbo.Client):
    2. self.unary = client.unary(
    3. method_name="sayHello",
    4. request_serializer=greeter_pb2.GreeterRequest.SerializeToString,
    5. response_deserializer=greeter_pb2.GreeterReply.FromString,
    6. )
    7. def say_hello(self, request):
    8. return self.unary(request)
  1. if __name__ == "__main__":
  2. reference_config = ReferenceConfig.from_url(
  3. "tri://127.0.0.1:50051/org.apache.dubbo.samples.proto.Greeter"
  4. )
  5. dubbo_client = dubbo.Client(reference_config)
  6. stub = GreeterServiceStub(dubbo_client)
  7. result = stub.say_hello(greeter_pb2.GreeterRequest(name="hello"))
  8. print(result.message)
  9. ```
  10. server
  11. ```
  12. def say_hello(request):
  13. print(f"Received request: {request}")
  14. return greeter_pb2.GreeterReply(message=f"{request.name} Dubbo!")
  15. if __name__ == "__main__":
  16. # build a method handler
  17. method_handler = RpcMethodHandler.unary(
  18. say_hello,
  19. request_deserializer=greeter_pb2.GreeterRequest.FromString,
  20. response_serializer=greeter_pb2.GreeterReply.SerializeToString,
  21. )
  22. # build a service handler
  23. service_handler = RpcServiceHandler(
  24. service_name="org.apache.dubbo.samples.proto.Greeter",
  25. method_handlers={"sayHello": method_handler},
  26. )
  27. service_config = ServiceConfig(service_handler)
  28. # start the server
  29. server = dubbo.Server(service_config).start()
  30. input("Press Enter to stop the server...\n")
  31. ```

Json

protobuf does not fully illustrate how to implement custom serialization and deserialization because its built-in functions perfectly meet the requirements. Instead, I’ll demonstrate how to create custom serialization and deserialization functions using orjson:

  1. Install orjson:

    1. pip install orjson
  2. Define serialization and deserialization functions:

    client

    ``` def request_serializer(data: Dict) -> bytes:

    1. return orjson.dumps(data)
  1. def response_deserializer(data: bytes) -> Dict:
  2. return orjson.loads(data)
  3. class GreeterServiceStub:
  4. def __init__(self, client: dubbo.Client):
  5. self.unary = client.unary(
  6. method_name="unary",
  7. request_serializer=request_serializer,
  8. response_deserializer=response_deserializer,
  9. )
  10. def say_hello(self, request):
  11. return self.unary(request)
  12. if __name__ == "__main__":
  13. reference_config = ReferenceConfig.from_url(
  14. "tri://127.0.0.1:50051/org.apache.dubbo.samples.serialization.json"
  15. )
  16. dubbo_client = dubbo.Client(reference_config)
  17. stub = GreeterServiceStub(dubbo_client)
  18. result = stub.say_hello({"name": "world"})
  19. print(result)
  20. ```
  21. server
  22. ```
  23. def request_deserializer(data: bytes) -> Dict:
  24. return orjson.loads(data)
  25. def response_serializer(data: Dict) -> bytes:
  26. return orjson.dumps(data)
  27. def handle_unary(request):
  28. print(f"Received request: {request}")
  29. return {"message": f"Hello, {request['name']}"}
  30. if __name__ == "__main__":
  31. # build a method handler
  32. method_handler = RpcMethodHandler.unary(
  33. handle_unary,
  34. request_deserializer=request_deserializer,
  35. response_serializer=response_serializer,
  36. )
  37. # build a service handler
  38. service_handler = RpcServiceHandler(
  39. service_name="org.apache.dubbo.samples.HelloWorld",
  40. method_handlers={"unary": method_handler},
  41. )
  42. service_config = ServiceConfig(service_handler)
  43. # start the server
  44. server = dubbo.Server(service_config).start()
  45. input("Press Enter to stop the server...\n")
  46. ```

Feedback

Was this page helpful?

Yes No

Last modified November 7, 2024: docs: add python sdk manual (#3056) (26c58b388ff)