Part I: Protocol Buffers

You have a new idea for an app. This should communicate strongly with a web server? Many would now start to write a RESTful-Api. Nice and old-fashioned. Maybe a little refreshed by Swagger. But in the end a JSON output of the database query. Readable for both man and machine. Why change anything?

REST is wonderful. Many different clients can use a single API. Just open a URL and read a JSON. But REST is also slow. It is distributed over an uncompressed Http/1.1 Furthermore, the data must first be translated into a JSON format and then back from this JSON format into variables or objects of the language used. Also, you may not want everyone to be able to read your API. After all it is the backend for your app.

The solution is called RPC. It is fast, because it is compressed and even possible to encrypt. RPC runs over the modern Http/2.0, it is binary and like CORBA language independent. A Service API with RPC can only be used by applications that know the underlying interface.

The interface we will use is the Google Protocol Buffers.

What are protocol buffers?

Protocol Buffers are a platform-independent language for serialization of structured data. They can be compared with XML. But smaller, faster and easier (according to Google). With them it is possible to create stubs for classes to share them between different systems.a

A small example:

syntax = "proto3"; // 1. define syntax

package net.rantzen; // 2. structure

// 3. message as class stub
message Test {
    uint64 _id = 1; // 4. ordered variables in stub
    string text = 2;
}
  1.  

First the syntax is defined. The latest version is 3, so we only use Proto3 and don’t care about backwards compatibility, because this is a new project.
As you know it e.g. from Java, you define a package where the stub is located. So you can use the same name for a message in different packages.
The actual stub of the class is defined as message. It is possible to define multiple messages in the same file and even messages within messages as nested stubs. More on this later.
The individual variables of a message are numbered and their type defined. A list of the possible types can be read here.

  1. First the syntax is defined. The latest version is 3, so we only use Proto3 and don’t care about backwards compatibility, because this is a new project.
  2. As you know it e.g. from Java, you define a package where the stub is located. So you can use the same name for a message in different packages.
  3. The actual stub of the class is defined as message. It is possible to define multiple messages in the same file and even messages within messages as nested stubs. More on this later.
  4. The individual variables of a message are numbered and their type defined. A list of the possible types can be read here.

Creating a Protocol Buffer Project

It is always best to learn something by imagining a project. Suppose we have an app where users can write down their thoughts. A simple note app. Notes are sent to a server and can be read from the server. So a simple note app with backup or cloud-sync. function.

What do we need?

  1. An user: User.proto
  2. A note: Note.proto

Our user needs an ID to identify him internally. In addition an email address and a password so that he can access his data again.

His notes of course need a text where the actual note is written. An ID for internal processing and various date specifications. A creation date and an update date. Plus a type. Whether it’s a new idea or a reminder.

So we create two stubs in Proto3 syntax:

Note.proto

syntax = "proto3";

package net.rantzen;

import "google/protobuf/timestamp.proto";

message Note {
    uint64 _id = 1;
    string text = 2;
    Date dates = 3;
    Type type = 4;

    enum Type {
        IDEA = 0;
        REMINDER = 1;
    }

    message Date {
        google.protobuf.Timestamp created = 1;
        google.protobuf.Timestamp updated = 2;
    }
}

In our Note.proto file the data is stored in a nested stub file. In this case unnecessary but nice to show that the numbering is not transferred to the substubs. They start again at 1. Furthermore we import the Google Stub Timestamp for our date. The type is represented as enum. Enums start at 0, not at 1, because they will have this value later in the real class.

User.proto

syntax = "proto3";

package net.rantzen;

import "Note.proto";

message User {
    uint64 _id = 1;
    string email = 2;
    string password = 3;
    repeated Note notes = 4;
}

In the User.proto we proceed similarly to the Note.proto. This time, however, we import the Note.proto we created earlier and create an entry Note notes. In front of it we put the word repeated. This will result in an array of notes.

Compiling the Stubs

Protocol Buffers are language neutral. There are natively supported languages and many compilers written by the community. In this example we are interfaced to JavaScript. JavaScript offers no options. Other languages need one. For Java, for example, our stubs need an entry for the Java package and the class name:

option java_package = "net.rantzen.protobuf";
option java_outer_classname = "UserProto";

Installing the compilers

To compile our files stubs, we must first install the compiler. You can find it here. If the compiler is installed and the path variable is set, we can continue.

Compilation

Since we want to have JavaScript we call the compiler with these arguments:

protoc -I=Proto/ – js_out="Proto/out/" User.proto Note.proto

This requires that we have a file structure that looks like this:

Proto/
 | out/
 | User.proto
 | Note.proto

With -I the place where our proto files are located is passed. –js_out says that we want to have a JavaScript file in the Proto/out/ folder. This folder must already exist. The compiler is not able to create folders. Finally we get the two files we want to compile: User.proto Note.proto.

Now we get two JavaScript files that we can use.

[su_spoiler title=”JavaScript Code”]

/**
 * @fileoverview
 * @enhanceable
 * @suppress {messageConventions} JS Compiler reports an error if a variable or
 *     field starts with 'MSG_' and isn't a translatable message.
 * @public
 */
// GENERATED CODE – DO NOT EDIT!

goog.provide('proto.net.rantzen.Note');
goog.provide('proto.net.rantzen.Note.Date');
goog.provide('proto.net.rantzen.Note.Type');

goog.require('jspb.BinaryReader');
goog.require('jspb.BinaryWriter');
goog.require('jspb.Message');
goog.require('proto.google.protobuf.Timestamp');


/**
 * Generated by JsPbCodeGenerator.
 * @param {Array=} opt_data Optional initial data array, typically from a
 * server response, or constructed directly in Javascript. The array is used
 * in place and becomes part of the constructed object. It is not cloned.
 * If no data is provided, the constructed object will be empty, but still
 * valid.
 * @extends {jspb.Message}
 * @constructor
 */
proto.net.rantzen.Note = function(opt_data) {
  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.net.rantzen.Note, jspb.Message);
if (goog.DEBUG && !COMPILED) {
  proto.net.rantzen.Note.displayName = 'proto.net.rantzen.Note';
}


if (jspb.Message.GENERATE_TO_OBJECT) {
/**
 * Creates an object representation of this proto suitable for use in Soy templates.
 * Field names that are reserved in JavaScript and will be renamed to pb_name.
 * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
 * For the list of reserved names please see:
 *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
 * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
 *     for transitional soy proto support: http://goto/soy-param-migration
 * @return {!Object}
 */
proto.net.rantzen.Note.prototype.toObject = function(opt_includeInstance) {
  return proto.net.rantzen.Note.toObject(opt_includeInstance, this);
};


/**
 * Static version of the {@see toObject} method.
 * @param {boolean|undefined} includeInstance Whether to include the JSPB
 *     instance for transitional soy proto support:
 *     http://goto/soy-param-migration
 * @param {!proto.net.rantzen.Note} msg The msg instance to transform.
 * @return {!Object}
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.net.rantzen.Note.toObject = function(includeInstance, msg) {
  var f, obj = {
    id: jspb.Message.getFieldWithDefault(msg, 1, 0),
    text: jspb.Message.getFieldWithDefault(msg, 2, ""),
    dates: (f = msg.getDates()) && proto.net.rantzen.Note.Date.toObject(includeInstance, f),
    type: jspb.Message.getFieldWithDefault(msg, 4, 0)
  };

  if (includeInstance) {
    obj.$jspbMessageInstance = msg;
  }
  return obj;
};
}


/**
 * Deserializes binary data (in protobuf wire format).
 * @param {jspb.ByteSource} bytes The bytes to deserialize.
 * @return {!proto.net.rantzen.Note}
 */
proto.net.rantzen.Note.deserializeBinary = function(bytes) {
  var reader = new jspb.BinaryReader(bytes);
  var msg = new proto.net.rantzen.Note;
  return proto.net.rantzen.Note.deserializeBinaryFromReader(msg, reader);
};


/**
 * Deserializes binary data (in protobuf wire format) from the
 * given reader into the given message object.
 * @param {!proto.net.rantzen.Note} msg The message object to deserialize into.
 * @param {!jspb.BinaryReader} reader The BinaryReader to use.
 * @return {!proto.net.rantzen.Note}
 */
proto.net.rantzen.Note.deserializeBinaryFromReader = function(msg, reader) {
  while (reader.nextField()) {
    if (reader.isEndGroup()) {
      break;
    }
    var field = reader.getFieldNumber();
    switch (field) {
    case 1:
      var value = /** @type {number} */ (reader.readUint64());
      msg.setId(value);
      break;
    case 2:
      var value = /** @type {string} */ (reader.readString());
      msg.setText(value);
      break;
    case 3:
      var value = new proto.net.rantzen.Note.Date;
      reader.readMessage(value,proto.net.rantzen.Note.Date.deserializeBinaryFromReader);
      msg.setDates(value);
      break;
    case 4:
      var value = /** @type {!proto.net.rantzen.Note.Type} */ (reader.readEnum());
      msg.setType(value);
      break;
    default:
      reader.skipField();
      break;
    }
  }
  return msg;
};


/**
 * Serializes the message to binary data (in protobuf wire format).
 * @return {!Uint8Array}
 */
proto.net.rantzen.Note.prototype.serializeBinary = function() {
  var writer = new jspb.BinaryWriter();
  proto.net.rantzen.Note.serializeBinaryToWriter(this, writer);
  return writer.getResultBuffer();
};


/**
 * Serializes the given message to binary data (in protobuf wire
 * format), writing to the given BinaryWriter.
 * @param {!proto.net.rantzen.Note} message
 * @param {!jspb.BinaryWriter} writer
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.net.rantzen.Note.serializeBinaryToWriter = function(message, writer) {
  var f = undefined;
  f = message.getId();
  if (f !== 0) {
    writer.writeUint64(
      1,
      f
    );
  }
  f = message.getText();
  if (f.length > 0) {
    writer.writeString(
      2,
      f
    );
  }
  f = message.getDates();
  if (f != null) {
    writer.writeMessage(
      3,
      f,
      proto.net.rantzen.Note.Date.serializeBinaryToWriter
    );
  }
  f = message.getType();
  if (f !== 0.0) {
    writer.writeEnum(
      4,
      f
    );
  }
};


/**
 * @enum {number}
 */
proto.net.rantzen.Note.Type = {
  IDEA: 0,
  REMINDER: 1
};


/**
 * Generated by JsPbCodeGenerator.
 * @param {Array=} opt_data Optional initial data array, typically from a
 * server response, or constructed directly in Javascript. The array is used
 * in place and becomes part of the constructed object. It is not cloned.
 * If no data is provided, the constructed object will be empty, but still
 * valid.
 * @extends {jspb.Message}
 * @constructor
 */
proto.net.rantzen.Note.Date = function(opt_data) {
  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.net.rantzen.Note.Date, jspb.Message);
if (goog.DEBUG && !COMPILED) {
  proto.net.rantzen.Note.Date.displayName = 'proto.net.rantzen.Note.Date';
}


if (jspb.Message.GENERATE_TO_OBJECT) {
/**
 * Creates an object representation of this proto suitable for use in Soy templates.
 * Field names that are reserved in JavaScript and will be renamed to pb_name.
 * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
 * For the list of reserved names please see:
 *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
 * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
 *     for transitional soy proto support: http://goto/soy-param-migration
 * @return {!Object}
 */
proto.net.rantzen.Note.Date.prototype.toObject = function(opt_includeInstance) {
  return proto.net.rantzen.Note.Date.toObject(opt_includeInstance, this);
};


/**
 * Static version of the {@see toObject} method.
 * @param {boolean|undefined} includeInstance Whether to include the JSPB
 *     instance for transitional soy proto support:
 *     http://goto/soy-param-migration
 * @param {!proto.net.rantzen.Note.Date} msg The msg instance to transform.
 * @return {!Object}
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.net.rantzen.Note.Date.toObject = function(includeInstance, msg) {
  var f, obj = {
    created: (f = msg.getCreated()) && proto.google.protobuf.Timestamp.toObject(includeInstance, f),
    updated: (f = msg.getUpdated()) && proto.google.protobuf.Timestamp.toObject(includeInstance, f)
  };

  if (includeInstance) {
    obj.$jspbMessageInstance = msg;
  }
  return obj;
};
}


/**
 * Deserializes binary data (in protobuf wire format).
 * @param {jspb.ByteSource} bytes The bytes to deserialize.
 * @return {!proto.net.rantzen.Note.Date}
 */
proto.net.rantzen.Note.Date.deserializeBinary = function(bytes) {
  var reader = new jspb.BinaryReader(bytes);
  var msg = new proto.net.rantzen.Note.Date;
  return proto.net.rantzen.Note.Date.deserializeBinaryFromReader(msg, reader);
};


/**
 * Deserializes binary data (in protobuf wire format) from the
 * given reader into the given message object.
 * @param {!proto.net.rantzen.Note.Date} msg The message object to deserialize into.
 * @param {!jspb.BinaryReader} reader The BinaryReader to use.
 * @return {!proto.net.rantzen.Note.Date}
 */
proto.net.rantzen.Note.Date.deserializeBinaryFromReader = function(msg, reader) {
  while (reader.nextField()) {
    if (reader.isEndGroup()) {
      break;
    }
    var field = reader.getFieldNumber();
    switch (field) {
    case 1:
      var value = new proto.google.protobuf.Timestamp;
      reader.readMessage(value,proto.google.protobuf.Timestamp.deserializeBinaryFromReader);
      msg.setCreated(value);
      break;
    case 2:
      var value = new proto.google.protobuf.Timestamp;
      reader.readMessage(value,proto.google.protobuf.Timestamp.deserializeBinaryFromReader);
      msg.setUpdated(value);
      break;
    default:
      reader.skipField();
      break;
    }
  }
  return msg;
};


/**
 * Serializes the message to binary data (in protobuf wire format).
 * @return {!Uint8Array}
 */
proto.net.rantzen.Note.Date.prototype.serializeBinary = function() {
  var writer = new jspb.BinaryWriter();
  proto.net.rantzen.Note.Date.serializeBinaryToWriter(this, writer);
  return writer.getResultBuffer();
};


/**
 * Serializes the given message to binary data (in protobuf wire
 * format), writing to the given BinaryWriter.
 * @param {!proto.net.rantzen.Note.Date} message
 * @param {!jspb.BinaryWriter} writer
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.net.rantzen.Note.Date.serializeBinaryToWriter = function(message, writer) {
  var f = undefined;
  f = message.getCreated();
  if (f != null) {
    writer.writeMessage(
      1,
      f,
      proto.google.protobuf.Timestamp.serializeBinaryToWriter
    );
  }
  f = message.getUpdated();
  if (f != null) {
    writer.writeMessage(
      2,
      f,
      proto.google.protobuf.Timestamp.serializeBinaryToWriter
    );
  }
};


/**
 * optional google.protobuf.Timestamp created = 1;
 * @return {?proto.google.protobuf.Timestamp}
 */
proto.net.rantzen.Note.Date.prototype.getCreated = function() {
  return /** @type{?proto.google.protobuf.Timestamp} */ (
    jspb.Message.getWrapperField(this, proto.google.protobuf.Timestamp, 1));
};


/** @param {?proto.google.protobuf.Timestamp|undefined} value */
proto.net.rantzen.Note.Date.prototype.setCreated = function(value) {
  jspb.Message.setWrapperField(this, 1, value);
};


proto.net.rantzen.Note.Date.prototype.clearCreated = function() {
  this.setCreated(undefined);
};


/**
 * Returns whether this field is set.
 * @return {!boolean}
 */
proto.net.rantzen.Note.Date.prototype.hasCreated = function() {
  return jspb.Message.getField(this, 1) != null;
};


/**
 * optional google.protobuf.Timestamp updated = 2;
 * @return {?proto.google.protobuf.Timestamp}
 */
proto.net.rantzen.Note.Date.prototype.getUpdated = function() {
  return /** @type{?proto.google.protobuf.Timestamp} */ (
    jspb.Message.getWrapperField(this, proto.google.protobuf.Timestamp, 2));
};


/** @param {?proto.google.protobuf.Timestamp|undefined} value */
proto.net.rantzen.Note.Date.prototype.setUpdated = function(value) {
  jspb.Message.setWrapperField(this, 2, value);
};


proto.net.rantzen.Note.Date.prototype.clearUpdated = function() {
  this.setUpdated(undefined);
};


/**
 * Returns whether this field is set.
 * @return {!boolean}
 */
proto.net.rantzen.Note.Date.prototype.hasUpdated = function() {
  return jspb.Message.getField(this, 2) != null;
};


/**
 * optional uint64 _id = 1;
 * @return {number}
 */
proto.net.rantzen.Note.prototype.getId = function() {
  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
};


/** @param {number} value */
proto.net.rantzen.Note.prototype.setId = function(value) {
  jspb.Message.setProto3IntField(this, 1, value);
};


/**
 * optional string text = 2;
 * @return {string}
 */
proto.net.rantzen.Note.prototype.getText = function() {
  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};


/** @param {string} value */
proto.net.rantzen.Note.prototype.setText = function(value) {
  jspb.Message.setProto3StringField(this, 2, value);
};


/**
 * optional Date dates = 3;
 * @return {?proto.net.rantzen.Note.Date}
 */
proto.net.rantzen.Note.prototype.getDates = function() {
  return /** @type{?proto.net.rantzen.Note.Date} */ (
    jspb.Message.getWrapperField(this, proto.net.rantzen.Note.Date, 3));
};


/** @param {?proto.net.rantzen.Note.Date|undefined} value */
proto.net.rantzen.Note.prototype.setDates = function(value) {
  jspb.Message.setWrapperField(this, 3, value);
};


proto.net.rantzen.Note.prototype.clearDates = function() {
  this.setDates(undefined);
};


/**
 * Returns whether this field is set.
 * @return {!boolean}
 */
proto.net.rantzen.Note.prototype.hasDates = function() {
  return jspb.Message.getField(this, 3) != null;
};


/**
 * optional Type type = 4;
 * @return {!proto.net.rantzen.Note.Type}
 */
proto.net.rantzen.Note.prototype.getType = function() {
  return /** @type {!proto.net.rantzen.Note.Type} */ (jspb.Message.getFieldWithDefault(this, 4, 0));
};


/** @param {!proto.net.rantzen.Note.Type} value */
proto.net.rantzen.Note.prototype.setType = function(value) {
  jspb.Message.setProto3EnumField(this, 4, value);
};


/**
 * @fileoverview
 * @enhanceable
 * @suppress {messageConventions} JS Compiler reports an error if a variable or
 *     field starts with 'MSG_' and isn't a translatable message.
 * @public
 */
// GENERATED CODE – DO NOT EDIT!

goog.provide('proto.net.rantzen.User');

goog.require('jspb.BinaryReader');
goog.require('jspb.BinaryWriter');
goog.require('jspb.Message');
goog.require('proto.net.rantzen.Note');


/**
 * Generated by JsPbCodeGenerator.
 * @param {Array=} opt_data Optional initial data array, typically from a
 * server response, or constructed directly in Javascript. The array is used
 * in place and becomes part of the constructed object. It is not cloned.
 * If no data is provided, the constructed object will be empty, but still
 * valid.
 * @extends {jspb.Message}
 * @constructor
 */
proto.net.rantzen.User = function(opt_data) {
  jspb.Message.initialize(this, opt_data, 0, -1, proto.net.rantzen.User.repeatedFields_, null);
};
goog.inherits(proto.net.rantzen.User, jspb.Message);
if (goog.DEBUG && !COMPILED) {
  proto.net.rantzen.User.displayName = 'proto.net.rantzen.User';
}
/**
 * List of repeated fields within this message type.
 * @private {!Array<number>}
 * @const
 */
proto.net.rantzen.User.repeatedFields_ = [4];



if (jspb.Message.GENERATE_TO_OBJECT) {
/**
 * Creates an object representation of this proto suitable for use in Soy templates.
 * Field names that are reserved in JavaScript and will be renamed to pb_name.
 * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
 * For the list of reserved names please see:
 *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
 * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
 *     for transitional soy proto support: http://goto/soy-param-migration
 * @return {!Object}
 */
proto.net.rantzen.User.prototype.toObject = function(opt_includeInstance) {
  return proto.net.rantzen.User.toObject(opt_includeInstance, this);
};


/**
 * Static version of the {@see toObject} method.
 * @param {boolean|undefined} includeInstance Whether to include the JSPB
 *     instance for transitional soy proto support:
 *     http://goto/soy-param-migration
 * @param {!proto.net.rantzen.User} msg The msg instance to transform.
 * @return {!Object}
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.net.rantzen.User.toObject = function(includeInstance, msg) {
  var f, obj = {
    id: jspb.Message.getFieldWithDefault(msg, 1, 0),
    email: jspb.Message.getFieldWithDefault(msg, 2, ""),
    password: jspb.Message.getFieldWithDefault(msg, 3, ""),
    notesList: jspb.Message.toObjectList(msg.getNotesList(),
    proto.net.rantzen.Note.toObject, includeInstance)
  };

  if (includeInstance) {
    obj.$jspbMessageInstance = msg;
  }
  return obj;
};
}


/**
 * Deserializes binary data (in protobuf wire format).
 * @param {jspb.ByteSource} bytes The bytes to deserialize.
 * @return {!proto.net.rantzen.User}
 */
proto.net.rantzen.User.deserializeBinary = function(bytes) {
  var reader = new jspb.BinaryReader(bytes);
  var msg = new proto.net.rantzen.User;
  return proto.net.rantzen.User.deserializeBinaryFromReader(msg, reader);
};


/**
 * Deserializes binary data (in protobuf wire format) from the
 * given reader into the given message object.
 * @param {!proto.net.rantzen.User} msg The message object to deserialize into.
 * @param {!jspb.BinaryReader} reader The BinaryReader to use.
 * @return {!proto.net.rantzen.User}
 */
proto.net.rantzen.User.deserializeBinaryFromReader = function(msg, reader) {
  while (reader.nextField()) {
    if (reader.isEndGroup()) {
      break;
    }
    var field = reader.getFieldNumber();
    switch (field) {
    case 1:
      var value = /** @type {number} */ (reader.readUint64());
      msg.setId(value);
      break;
    case 2:
      var value = /** @type {string} */ (reader.readString());
      msg.setEmail(value);
      break;
    case 3:
      var value = /** @type {string} */ (reader.readString());
      msg.setPassword(value);
      break;
    case 4:
      var value = new proto.net.rantzen.Note;
      reader.readMessage(value,proto.net.rantzen.Note.deserializeBinaryFromReader);
      msg.addNotes(value);
      break;
    default:
      reader.skipField();
      break;
    }
  }
  return msg;
};


/**
 * Serializes the message to binary data (in protobuf wire format).
 * @return {!Uint8Array}
 */
proto.net.rantzen.User.prototype.serializeBinary = function() {
  var writer = new jspb.BinaryWriter();
  proto.net.rantzen.User.serializeBinaryToWriter(this, writer);
  return writer.getResultBuffer();
};


/**
 * Serializes the given message to binary data (in protobuf wire
 * format), writing to the given BinaryWriter.
 * @param {!proto.net.rantzen.User} message
 * @param {!jspb.BinaryWriter} writer
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.net.rantzen.User.serializeBinaryToWriter = function(message, writer) {
  var f = undefined;
  f = message.getId();
  if (f !== 0) {
    writer.writeUint64(
      1,
      f
    );
  }
  f = message.getEmail();
  if (f.length > 0) {
    writer.writeString(
      2,
      f
    );
  }
  f = message.getPassword();
  if (f.length > 0) {
    writer.writeString(
      3,
      f
    );
  }
  f = message.getNotesList();
  if (f.length > 0) {
    writer.writeRepeatedMessage(
      4,
      f,
      proto.net.rantzen.Note.serializeBinaryToWriter
    );
  }
};


/**
 * optional uint64 _id = 1;
 * @return {number}
 */
proto.net.rantzen.User.prototype.getId = function() {
  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
};


/** @param {number} value */
proto.net.rantzen.User.prototype.setId = function(value) {
  jspb.Message.setProto3IntField(this, 1, value);
};


/**
 * optional string email = 2;
 * @return {string}
 */
proto.net.rantzen.User.prototype.getEmail = function() {
  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};


/** @param {string} value */
proto.net.rantzen.User.prototype.setEmail = function(value) {
  jspb.Message.setProto3StringField(this, 2, value);
};


/**
 * optional string password = 3;
 * @return {string}
 */
proto.net.rantzen.User.prototype.getPassword = function() {
  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
};


/** @param {string} value */
proto.net.rantzen.User.prototype.setPassword = function(value) {
  jspb.Message.setProto3StringField(this, 3, value);
};


/**
 * repeated Note notes = 4;
 * @return {!Array<!proto.net.rantzen.Note>}
 */
proto.net.rantzen.User.prototype.getNotesList = function() {
  return /** @type{!Array<!proto.net.rantzen.Note>} */ (
    jspb.Message.getRepeatedWrapperField(this, proto.net.rantzen.Note, 4));
};


/** @param {!Array<!proto.net.rantzen.Note>} value */
proto.net.rantzen.User.prototype.setNotesList = function(value) {
  jspb.Message.setRepeatedWrapperField(this, 4, value);
};


/**
 * @param {!proto.net.rantzen.Note=} opt_value
 * @param {number=} opt_index
 * @return {!proto.net.rantzen.Note}
 */
proto.net.rantzen.User.prototype.addNotes = function(opt_value, opt_index) {
  return jspb.Message.addToRepeatedWrapperField(this, 4, opt_value, proto.net.rantzen.Note, opt_index);
};


proto.net.rantzen.User.prototype.clearNotesList = function() {
  this.setNotesList([]);
};


[/su_spoiler]

Use

Coming soon…

In summary, protocol buffers are manually written stubs of a theoretical class for communication between systems.


If it helped you, or you have constructive criticism, please write me a comment :).

How useful was this post?

Click on a star to rate it!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?


Arne Rantzen

He has been programming in various languages for more than 15 years. For about 10 years in a semi-professional way. He received a Bachelor of Science at the elite University of Tübingen and is currently a Master student in Computer Science. Since 2020 he works as a research assistant at karriere tutor.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *