Protocol Buffer interoperability between go and JavaScript (using closure-library's goog.proto2)

Andy Hochhaus 830501ffbd Remove use of non-native extensions 10 months ago
protoc-gen-js 830501ffbd Remove use of non-native extensions 10 months ago
.gitignore 977188b57a Initial commit 4 years ago
LICENSE 484b7b9cd5 Add protoc-gen-js and documentation additions. 2 years ago
Makefile 484b7b9cd5 Add protoc-gen-js and documentation additions. 2 years ago
README.md 86cd949d29 Updates for code.taxi hosting 1 year ago
package_test.proto 830501ffbd Remove use of non-native extensions 10 months ago
pblite.go 484b7b9cd5 Add protoc-gen-js and documentation additions. 2 years ago
pbobject.go 484b7b9cd5 Add protoc-gen-js and documentation additions. 2 years ago
protoclosure.go 484b7b9cd5 Add protoc-gen-js and documentation additions. 2 years ago
protoclosure_test.go 86cd949d29 Updates for code.taxi hosting 1 year ago
test.proto 830501ffbd Remove use of non-native extensions 10 months ago
utils.go 484b7b9cd5 Add protoc-gen-js and documentation additions. 2 years ago

README.md

protoclosure

Protocol Buffer interoperability between Go's protobuf and closure-library's goog.proto2 JavaScript implementation.

JS Usage

First, compile your *.pb.js file(s) with protoc:

$ cat src/simple/simple.proto
syntax = "proto2";

message Simple {
  optional string foo = 1;
}
$ protoc --plugin=bin/protoc-js-go --js_out=. src/simple/simple.proto

Next, goog.require the Simple package and use goog.json to parse and serialize the JSON based encodings. Also, consider adding --define=goog.json.USE_NATIVE_JSON=true to your compile for improved security and runtime performance.

goog.provide('example');

goog.require('Simple');
goog.require('goog.json');
goog.require('goog.proto2.ObjectSerializer');


/**
 * Example protobuf usage.
 */
example = function() {
  // create a 'Hello World' message
  var s = new Simple();
  s.setFoo('Hello World');

  // serialize the Simple message using the PBObject format
  var serializer = new goog.proto2.ObjectSerializer();
  var obj = serializer.serialize(s);
  var jsonMsg = goog.json.serialize(obj);

  // parse the PBObject format jsonMsg into a second protocol buffer message
  var obj2 = goog.json.parse(jsonMsg);
  var serializer2 = new goog.proto2.ObjectSerializer();
  var s2 = /** @type {!Simple} */ (serializer2.deserialize(
      Simple.getDescriptor(), obj2));

  // ensure values are equal
  if (s.getFoo() != s2.getFoo()) {
    alert('Values are not equal: ' + s.getFoo() + '. ' + s2.getFoo() + '.');
  }
};

Go Usage

First, compile a *.pb.go package from a *.proto file using protoc with the go protobuf plugin:

$ protoc --plugin=bin/protoc-gen-go --go_out=. src/simple/simple.proto
$ # or if you want to generate both JS and Go with a single command
$ protoc --plugin=bin/protoc-gen-js --plugin=bin/protoc-gen-go --js_out=. \
    --go_out=. src/simple/simple.proto

Next, import the simple package and use protoclosure to Marshal and Unmarshal from the various JSON based encodings (see PBLite and PBObject below).

package main

import (
  "log"

  "simple"

  "github.com/golang/protobuf/proto"
  "code.taxi/samegoal/protoclosure"
)

func main() {
  s := &simple.Simple{}
  s.Foo = proto.String("Hello World")

  jsonMsg, err := protoclosure.MarshalObjectKeyTag(s)
  if err != nil {
    log.Fatal(err)
  }

  s2 := &simple.Simple{}
  if err := protoclosure.UnmarshalObjectKeyTag(jsonMsg, s2); err != nil {
    log.Fatal(err)
  }

  if *s.Foo != *s2.Foo {
    log.Fatalf("Values not equal: %s. %s.", *s.Foo, *s2.Foo)
  }
}

Go API documentation

PBLite format

Example message:

message Person {
  optional int32 id = 1;
  optional string name = 2;
  optional string email = 3;
}

Example encoding:

[null,1,null,"user@example.com"]

Example encoding (zero-index):

[1,null,"user@example.com"]

PBObject format

Example message:

message Person {
  optional int32 id = 1;
  optional string name = 2;
  optional string email = 3;
}

Example encoding (tag name):

{"id":1,"email":"user@example.com"}

Example encoding (tag number):

{"1":1,"3":"user@example.com"}

protoclosure development

$ # setup environment (GOPATH, etc)
$ go get code.taxi/samegoal/protoclosure
$ cd code.taxi/samegoal/protoclosure
$ # modify the source
$ go test -race
$ make  # run vet/fmt/lint, prior to sending Pull Request

To regenerate unit test protobuf files:

$ protoc --go_out=. code.taxi/samegoal/protoclosure/test.proto
$ protoc --go_out=. code.taxi/samegoal/protoclosure/package_test.proto

$ mv code.taxi/samegoal/protoclosure/test.pb.go code.taxi/samegoal/protoclosure/test.pb/
$ mv code.taxi/samegoal/protoclosure/package_test.pb.go code.taxi/samegoal/protoclosure/package_test.pb/

Unlicensed example files

Please note that the test files test.proto and package_test.proto are not included under the same BSD-style license as the rest of this package. These files are not part of closure-library itself, but instead were provided by some helpful Googlers on closure-library-discuss. Since that time they have been slightly modified as part of this project to remain current with upstream changes to goog.proto2. The *.pb.js reference files which are generated based upon these files are included in closure-library.

License

Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

Special Thanks