protobufjs / protobuf.js

Protocol Buffers for JavaScript & TypeScript.
Other
9.89k stars 1.41k forks source link

Float should be float instead of int when it's like 123.0 #1260

Open tony612 opened 5 years ago

tony612 commented 5 years ago

protobuf.js version: 6.8.8

Float field should always be float instead of int. But 123.0 will be converted to 123 using Number()

syntax = "proto3";
package test;

message Message {
    float foo1 = 1;
    float foo2 = 2;
}
var protobuf = require('protobufjs');

protobuf.load("test.proto", function (err, root) {
  if (err)
    throw err;

  var Message = root.lookupType("test.Message");

  var payload = { foo1: 123.0, foo2: 123.5 };
  var errMsg = Message.verify(payload);
  if (errMsg)
    throw Error(errMsg);
  var message = Message.create(payload);
  var buffer = Message.encode(message).finish();
  var message = Message.decode(buffer);
  console.log(message);
  // Message { foo1: 123, foo2: 123.5 }

});
iFwu commented 5 years ago

Hello, it's obviously that javascript doesn't have a such int type numbr. See below:

image

tony612 commented 5 years ago

But if the value is used as a JSON response, it's different.

iFwu commented 5 years ago

No, it's the same. Check out the json specification for number.

tony612 commented 5 years ago

@iFwu The problem is the receivers will have a problem like Android clients probably can't handle this when 123 is returned instead of 123.0. We can't say they are the same just because Javascript doesn't have a good type system.

iFwu commented 5 years ago

你都定义了float安卓怎么可能收到int?JS数字就是IEEE 754标准的,然后你在proto里定义了什么类型就是什么类型。

tony612 commented 5 years ago

@iFwu Please see my code above, foo1 is int after decoding.

iFwu commented 5 years ago

你哪看的foo1是int了?typeof foo1 === 'number' number就是number

tony612 commented 5 years ago

@iFwu But if you pass foo1 to the HTTP response, clients will receive int, right? Like

{foo: foo1} # This is returned as JSON response
tony612 commented 5 years ago

Let me describe more about the situation. We have a nodejs HTTP server, which calls a gRPC server. In the Nodejs server, the response received from the gRPC server will be used to returned to HTTP client. In this case, clients like Android will receive int instead of float.

iFwu commented 5 years ago

Let me describe more about the situation. We have a nodejs HTTP server, which calls a gRPC server. In the Nodejs server, the response received from the gRPC server will be used to returned to HTTP client. In this case, clients like Android will receive int instead of float.

So there are actual two problems in your situation:

  1. When the protobuf float field decoded in JavaScript, the meta type information float lost.
  2. When send response using Node.js and json format, you can't ensure the numeric type to be correct. (JSON doesn't have a difference between int and float)

Obviously, you cannot expect protobuf.js to solve your problems. The protobuf.js lib aims to encode data from JS and decode data from protobuf binary. And all of the jobs are done correctly.

IMO, you can still use protobuf to solve the problem 2, just simply replace the response format from json to protobuf. And you will get the correct type in Android client.