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

Proto3 canonical JSON support #1304

Open
johncsnyder opened this issue Sep 27, 2019 · 2 comments
Open

Proto3 canonical JSON support #1304

johncsnyder opened this issue Sep 27, 2019 · 2 comments

Comments

@johncsnyder
Copy link

johncsnyder commented Sep 27, 2019

There are a number of open issues related to this. According to #351:

Not yet supported:

"NaN", "Infinity" strings for floats
Any, Timestamp, Duration, Struct, Wrappers, FieldMask, ListValue, Value, NullValue are handled like messages
Feel free to reopen!

Any type url fix:

Struct, Value:

Related:

@johncsnyder
Copy link
Author

johncsnyder commented Sep 27, 2019

I have a working implementation that supports Timestamp and Duration well-known types here johncsnyder@a6eddb4

It probably needs a bit of work before making a PR, as it does not support all the cases covered under https://developers.google.com/protocol-buffers/docs/proto3#json and it changes the default toJSON functionality to output Timestamp and Duration as their string representations. Would appreciate some guidance here and how to incorporate this into protobufjs without breaking existing usage.

It creates the following wrappers

// Custom wrapper for Timestamp
wrappers[".google.protobuf.Timestamp"] = {
    fromObject: function(object) {
        if (typeof object === "string") {
            const ts = new Date(object);
            const seconds = Math.floor(ts.getTime() / 1000);
            const nanos = ts.getMilliseconds() * 1000000;
            return this.create({
                seconds: seconds,
                nanos: nanos
            });
        } else if (object instanceof Date) {
            const seconds = Math.floor(object.getTime() / 1000);
            const nanos = object.getMilliseconds() * 1000000;
            return this.create({
                seconds: seconds,
                nanos: nanos
            });
        }

        return this.fromObject(object);
    },

    toObject: function(message, options) {
        if (options && options.json) {
            return new Date(message.seconds * 1000 + message.nanos / 1000000);
        }
        return this.toObject(message, options);
    }
};

// Custom wrapper for Duration
wrappers[".google.protobuf.Duration"] = {
    fromObject: function(object) {
        if (typeof object === "string") {
            const unit = function() {
                if (object.slice(-1) == "s") return 1;
                if (object.slice(-1) == "m") return 60;
                if (object.slice(-1) == "h") return 60 * 60;
                if (object.slice(-1) == "d") return 60 * 60 * 24;
                throw new Error("invalid duration unit : must be one of s, m, h, or d")
            }();
            const value = parseInt(object.slice(0,-1));
            const seconds = value * unit;
            return this.create({
                seconds: seconds,
                nanos: 0,
            });
        }
        return this.fromObject(object);
    },

    toObject: function(message, options) {
        if (options && options.json && message.nanos == 0) {
            return message.seconds.toString() + "s"
        }
        return this.toObject(message, options);
    }
};

It also relaxes the object type check for Timestamp and Duration to support parsing the default message object structure as well as the string representation Eg parsing both {seconds: 1234, nanos: 5678} or 2019-01-01T00:00:00Z are supported for Timestamp.

@ntindall
Copy link

Related: #1258

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants