bufbuild/protobuf-es

Register Default Registry

Closed this issue · 3 comments

Summary

Add the ability to register and add types to a default registry that, unless otherwise specified, will be used as the typeRegistry option for json serilization.

Overview

One of the desing choices for protobuf-es was to not automatically generate a global registry as it can cause issues with conflicting versions of the same protobuf being used, as in the golang and java protobuf libraries. This is a good design chooices, however it does lead to more verbose code when serializing to json with any or extensions. The libary has registries that can be used to let the code know how it should serialize them. This is passed to the JSON serialization as the typeRegistry. Currently this has to be passed into every time a protobuf is serialized which can get quite repetitive and lead to errors if it is accidently omitted. Allowing types to be optionally set would not run necessitate running into the same collision issue as it is not registering them during import and instead would require the end application to specify which types they would like to be inserted. Additionally, this proposal would only use the default type registry if one is not supplied to the sterilization option, which would also reduce the chances off a conflict impacting an application.

Current syntax

const typeRegistry = createRegistry(age, hobbies);
user.toJsonString({ typeRegistry }); 

The following is a potential syntax for this:

Set the global default registry

const typeRegistry = createRegistry(age, hobbies);
setDefaultRegistry(typeRegistry ); // 

user.toJsonString(); 

Or let it add types to the default registry

addToDefaultRegistry(age, hobbies);
user.toJsonString();

Alternatively this could be expanded to allow for the setting of a default options from all serialization options as it is likely that an application would like to use consistent options for its sterilization.

My current workaround is by using a protobuf-es plugin that creates a class for a service that injects a registry into the service and then passes into the sterilization options. This works well for automating interaction with a specific service, but it gets quite repatitive in code that isn't generated by a plugin

https://github.com/Nova38/saacs/blob/29af08a15bce8419a25c96e36cd1b4e9b7484dc4/pkg/cmd/protoc-gen-es-saacs/src/generators/gateway.ts

Hey Thomas, we've been thinking about a default registry too.

In many use cases of Protobuf, there will be a layer on top that makes it easy to pass in a registry for all serialization. For example, RPCs in Connect-ES all use the type registry passed in through the JSON options for the transport:

https://github.com/connectrpc/connect-es/blob/084f9d37ad3b4ebcfc720f558b86e0e5df22c6cd/packages/connect-web/src/connect-transport.ts#L95-L99

But that leaves many other contexts, like manually unpacking an Any, using size-delimited message streams, or simply serializing a message for logging. A default registry seems like it could be convenient for these cases.

But I can also see it complicating the situation, leading to unexpected behavior. I agree that passing a registry explicitly should override the default one, but I think that we need a bit more capabilities to manage registries to make it work out nicely. For example, #679.

Thanks for opening the issue! Let's use it to investigate a good API around this further.

We've investigated adding a "default" registry, but decided against the feature for the following reasons:

  • Protobuf is most often used for RPC, and RPC frameworks should accept serialization options so that users can discard unknown fields, use JSON instead of binary, etc. The registry is already part of the serialization options, and a "default" registry adds ambiguity.
  • For unpacking a google.protobuf.Any, we'd have to make the registry argument optional to make use of a default registry. But a registry is required to unpack, so the signature would become ambiguous.
  • With the upcoming version 2, it is trivial to use custom serialization functions to implement a project-specific standard registry, see #896.