Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot encode message google.protobuf.Any in the v2.0.0-alpha #1192

Closed
biziosan opened this issue Aug 28, 2024 · 2 comments
Closed

Cannot encode message google.protobuf.Any in the v2.0.0-alpha #1192

biziosan opened this issue Aug 28, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@biziosan
Copy link

biziosan commented Aug 28, 2024

Describe the bug

When I use google.Any in my RPC arguments I get a "[internal] cannot encode message google.protobuf.Any to JSON: "type.googleapis.com/TestObject" is not in the type registry" message when calling the RPC.

To Reproduce

D:\projects\sd\versioned\sarah\projects\terra\node_modules\@connectrpc\connect\dist\cjs\protocol-connect\error-json.js:57
    const error = new connect_error_js_1.ConnectError(message !== null && message !== void 0 ? message : "", code, metadata);
                  ^

ConnectError: [internal] cannot encode message google.protobuf.Any to JSON: "type.googleapis.com/TestObject" is not in the type registry
    at errorFromJson (D:\projects\sd\versioned\sarah\projects\terra\node_modules\@connectrpc\connect\dist\cjs\protocol-connect\error-json.js:57:19)
    at next (D:\projects\sd\versioned\sarah\projects\terra\node_modules\@connectrpc\connect-web\dist\cjs\connect-transport.js:90:68)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.unary (D:\projects\sd\versioned\sarah\projects\terra\node_modules\@connectrpc\connect-web\dist\cjs\connect-transport.js:55:20)
    at async Object.requestTest (D:\projects\sd\versioned\sarah\projects\terra\node_modules\@connectrpc\connect\dist\cjs\promise-client.js:70:26) {
  rawMessage: 'cannot encode message google.protobuf.Any to JSON: "type.googleapis.com/TestObject" is not in the type registry',
  code: 13,
  metadata: Headers {
    [Symbol(headers list)]: HeadersList {
      cookies: null,
      [Symbol(headers map)]: Map(5) {
        'connection' => { name: 'connection', value: 'keep-alive' },
        'content-length' => { name: 'content-length', value: '145' },
        'content-type' => { name: 'content-type', value: 'application/json' },
        'date' => { name: 'date', value: 'Wed, 28 Aug 2024 10:54:38 GMT' },
        'keep-alive' => { name: 'keep-alive', value: 'timeout=5' }
      },
      [Symbol(headers map sorted)]: null
    },
    [Symbol(guard)]: 'none'
  },
  details: [],
  cause: undefined
}

Node.js v20.14.0

Process finished with exit code 1

Returning a non-Any message works as expected.


These are the .proto files used:

import "google/protobuf/any.proto";

message TestAny
{
    google.protobuf.Any object = 1000;
}
message TestObject
{
    uint32 n = 1000;
}
message TestRequest
{
    string r = 1000;
}
service TestService
{
    rpc RequestTest(TestRequest) returns (TestAny);
}

This reduced example generates the error:

function createServer()
{
    const rpcHandler = cnrpc.connectNodeAdapter(
        {
            routes: function(router: crpc.ConnectRouter) {
                router.service(TestService, {
                    requestTest(request: TestRequest): TestAny
                    {
                        const o = proto.create(TestObjectSchema, { n: 9 });
                        const a = proto_wkt.anyPack(TestObjectSchema, o);

                        return proto.create(TestAnySchema, { object: a });
                    },
                });
            }
        }
    );

    http.createServer(rpcHandler).listen(8099);
}

(async () => {
    createServer();

    const transport = crpc_web.createConnectTransport({ baseUrl: 'http://127.0.0.1:8099' });

    const client = crpc.createPromiseClient(TestService, transport);
    client.requestTest({ r: 'test' }).then((response) => {
            console.log(response);
    });
})();

Environment (please complete the following information):

  • @connectrpc/connect-web version: 2.0.0-alpha.1
  • @connectrpc/connect-node version: 2.0.0-alpha.1
  • Frontend framework and version: n/a
  • Node.js version: v20.14.0
  • Browser and version: n/a

Additional context
Add any other context about the problem here.

@timostamm
Copy link
Member

Hey @biziosan, thanks for giving the alpha a try!

google.protobuf.Any stores arbitrary messages in it's fields string type_url (for the type name) and bytes value (for the serialized content).

In the JSON format, Any doesn't simply serialize the two fields: Instead, the contained message is serialized to JSON, and the type name is added in the @type property.

So to serialize Any to JSON, it's necessary to parse the contained message first. And for this step, it's necessary to know the schema. Similar for parsing Any from JSON.

There is a simple solution to the problem: You can create a registry with the types you want to allow for Any, and pass the registry to the router via jsonOptions:

import { createRegistry } from "@bufbuild/protobuf";
import { connectNodeAdapter } from "@connectrpc/connect";

connectNodeAdapter({
  routes,
  jsonOptions: {
    registry: createRegistry(TestObjectSchema),
  },
});

@biziosan
Copy link
Author

biziosan commented Sep 2, 2024

Hi @timostamm, thank you for this new version! I am looking forward to working with it.

Thank you for looking at this issue. I made the changes you suggested (the new code is below), and it works now! I added the registry for both the encode and decode sides. In my main application, I already have the full registry, so I will give it to the JSON options.

function createServer()
{
    const rpcHandler = cnrpc.connectNodeAdapter(
        {
            routes: function(router: crpc.ConnectRouter) {
                router.service(TestService, {
                    requestTest(request: TestRequest): TestAny
                    {
                        const o = proto.create(TestObjectSchema, { n: 9 });
                        const a = proto_wkt.anyPack(TestObjectSchema, o);

                        return proto.create(TestAnySchema, { object: a });
                    },
                });
            },
            jsonOptions: {
                registry: proto.createRegistry(TestObjectSchema),
            }
        }
    );

    http.createServer(rpcHandler).listen(8099);
}

(async () => {
    createServer();

    const transport = crpc_web.createConnectTransport(
        {
            baseUrl: 'http://127.0.0.1:8099',
            jsonOptions: {
                registry: proto.createRegistry(TestObjectSchema),
            }
        });

    const client = crpc.createPromiseClient(TestService, transport);
    client.requestTest({ r: 'test' }).then((response) => {
            console.log(response);
    });
})();

@biziosan biziosan closed this as completed Sep 2, 2024
timostamm added a commit to connectrpc/connectrpc.com that referenced this issue Sep 3, 2024
smaye81 pushed a commit to connectrpc/connectrpc.com that referenced this issue Sep 30, 2024
smaye81 pushed a commit to connectrpc/connectrpc.com that referenced this issue Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants
@timostamm @biziosan and others