Merge pull request #6497 from murgatroid99/backport_node_protoc_examples

Backport node protoc examples
diff --git a/examples/node/README.md b/examples/node/README.md
index 2887883..59fb4a1 100644
--- a/examples/node/README.md
+++ b/examples/node/README.md
@@ -22,18 +22,24 @@
 TRY IT!
 -------
 
+There are two ways to generate the code needed to work with protocol buffers in Node.js - one approach uses [Protobuf.js](https://github.com/dcodeIO/ProtoBuf.js/) to dynamically generate the code at runtime, the other uses code statically generated using the protocol buffer compiler `protoc`. The examples behave identically, and either server can be used with either client.
+
  - Run the server
 
    ```sh
    $ # from this directory
-   $ node ./greeter_server.js &
+   $ node ./dynamic_codegen/greeter_server.js &
+   $ # OR
+   $ node ./static_codegen/greeter_server.js &
    ```
 
  - Run the client
 
    ```sh
    $ # from this directory
-   $ node ./greeter_client.js
+   $ node ./dynamic_codegen/greeter_client.js
+   $ # OR
+   $ node ./dynamic_codegen/greeter_client.js
    ```
 
 TUTORIAL
diff --git a/examples/node/dynamic_codegen/README.md b/examples/node/dynamic_codegen/README.md
new file mode 100644
index 0000000..1a6ec17
--- /dev/null
+++ b/examples/node/dynamic_codegen/README.md
@@ -0,0 +1 @@
+This is the dynamic code generation variant of the Node examples. Code in these examples is generated at runtime using Protobuf.js.
diff --git a/examples/node/greeter_client.js b/examples/node/dynamic_codegen/greeter_client.js
similarity index 96%
rename from examples/node/greeter_client.js
rename to examples/node/dynamic_codegen/greeter_client.js
index 2820acb..e24fb07 100644
--- a/examples/node/greeter_client.js
+++ b/examples/node/dynamic_codegen/greeter_client.js
@@ -31,7 +31,7 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../protos/helloworld.proto';
+var PROTO_PATH = __dirname + '/../../protos/helloworld.proto';
 
 var grpc = require('grpc');
 var hello_proto = grpc.load(PROTO_PATH).helloworld;
diff --git a/examples/node/greeter_server.js b/examples/node/dynamic_codegen/greeter_server.js
similarity index 96%
rename from examples/node/greeter_server.js
rename to examples/node/dynamic_codegen/greeter_server.js
index e7ad51f..aa43e4c 100644
--- a/examples/node/greeter_server.js
+++ b/examples/node/dynamic_codegen/greeter_server.js
@@ -31,7 +31,7 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../protos/helloworld.proto';
+var PROTO_PATH = __dirname + '/../../protos/helloworld.proto';
 
 var grpc = require('grpc');
 var hello_proto = grpc.load(PROTO_PATH).helloworld;
diff --git a/examples/node/route_guide/README.md b/examples/node/dynamic_codegen/route_guide/README.md
similarity index 100%
copy from examples/node/route_guide/README.md
copy to examples/node/dynamic_codegen/route_guide/README.md
diff --git a/examples/node/route_guide/route_guide_client.js b/examples/node/dynamic_codegen/route_guide/route_guide_client.js
similarity index 98%
rename from examples/node/route_guide/route_guide_client.js
rename to examples/node/dynamic_codegen/route_guide/route_guide_client.js
index fd05a59..775b9ad 100644
--- a/examples/node/route_guide/route_guide_client.js
+++ b/examples/node/dynamic_codegen/route_guide/route_guide_client.js
@@ -31,7 +31,7 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../../protos/route_guide.proto';
+var PROTO_PATH = __dirname + '/../../../protos/route_guide.proto';
 
 var async = require('async');
 var fs = require('fs');
diff --git a/examples/node/route_guide/route_guide_db.json b/examples/node/dynamic_codegen/route_guide/route_guide_db.json
similarity index 100%
copy from examples/node/route_guide/route_guide_db.json
copy to examples/node/dynamic_codegen/route_guide/route_guide_db.json
diff --git a/examples/node/route_guide/route_guide_server.js b/examples/node/dynamic_codegen/route_guide/route_guide_server.js
similarity index 98%
rename from examples/node/route_guide/route_guide_server.js
rename to examples/node/dynamic_codegen/route_guide/route_guide_server.js
index 6c01fac..6d59348 100644
--- a/examples/node/route_guide/route_guide_server.js
+++ b/examples/node/dynamic_codegen/route_guide/route_guide_server.js
@@ -31,7 +31,7 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../../protos/route_guide.proto';
+var PROTO_PATH = __dirname + '/../../../protos/route_guide.proto';
 
 var fs = require('fs');
 var parseArgs = require('minimist');
diff --git a/examples/node/package.json b/examples/node/package.json
index d135df2..2cae031 100644
--- a/examples/node/package.json
+++ b/examples/node/package.json
@@ -3,7 +3,8 @@
   "version": "0.1.0",
   "dependencies": {
     "async": "^1.5.2",
-    "grpc": "0.13.0",
+    "google-protobuf": "^3.0.0-alpha.5",
+    "grpc": "^0.14.0",
     "lodash": "^4.6.1",
     "minimist": "^1.2.0"
   }
diff --git a/examples/node/static_codegen/README.md b/examples/node/static_codegen/README.md
new file mode 100644
index 0000000..fc97d34
--- /dev/null
+++ b/examples/node/static_codegen/README.md
@@ -0,0 +1,7 @@
+This is the static code generation variant of the Node examples. Code in these examples is pre-generated using protoc and the Node gRPC protoc plugin, and the generated code can be found in various `*_pb.js` files. The command line sequence for generating those files is as follows (assuming that `protoc` and `grpc_node_plugin` are present, and starting in the base directory of this package):
+
+```sh
+cd ../protos
+protoc --js_out=import_style=commonjs,binary:../node/static_codegen/ --grpc_out=../node/static_codegen --plugin=protoc-gen-grpc=grpc_node_plugin helloworld.proto
+protoc --js_out=import_style=commonjs,binary:../node/static_codegen/route_guide/ --grpc_out=../node/static_codegen/route_guide/ --plugin=protoc-gen-grpc=grpc_node_plugin route_guide.proto
+```
diff --git a/examples/node/greeter_client.js b/examples/node/static_codegen/greeter_client.js
similarity index 80%
copy from examples/node/greeter_client.js
copy to examples/node/static_codegen/greeter_client.js
index 2820acb..da80cf3 100644
--- a/examples/node/greeter_client.js
+++ b/examples/node/static_codegen/greeter_client.js
@@ -31,22 +31,24 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../protos/helloworld.proto';
+var messages = require('./helloworld_pb');
+var services = require('./helloworld_grpc_pb');
 
 var grpc = require('grpc');
-var hello_proto = grpc.load(PROTO_PATH).helloworld;
 
 function main() {
-  var client = new hello_proto.Greeter('localhost:50051',
-                                       grpc.credentials.createInsecure());
+  var client = new services.GreeterClient('localhost:50051',
+                                          grpc.credentials.createInsecure());
   var user;
   if (process.argv.length >= 3) {
     user = process.argv[2];
   } else {
     user = 'world';
   }
-  client.sayHello({name: user}, function(err, response) {
-    console.log('Greeting:', response.message);
+  var request = new messages.HelloRequest();
+  request.setName(user);
+  client.sayHello(request, function(err, response) {
+    console.log('Greeting:', response.getMessage());
   });
 }
 
diff --git a/examples/node/greeter_server.js b/examples/node/static_codegen/greeter_server.js
similarity index 87%
copy from examples/node/greeter_server.js
copy to examples/node/static_codegen/greeter_server.js
index e7ad51f..a1591b8 100644
--- a/examples/node/greeter_server.js
+++ b/examples/node/static_codegen/greeter_server.js
@@ -31,16 +31,18 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../protos/helloworld.proto';
+var messages = require('./helloworld_pb');
+var services = require('./helloworld_grpc_pb');
 
 var grpc = require('grpc');
-var hello_proto = grpc.load(PROTO_PATH).helloworld;
 
 /**
  * Implements the SayHello RPC method.
  */
 function sayHello(call, callback) {
-  callback(null, {message: 'Hello ' + call.request.name});
+  var reply = new messages.HelloReply();
+  reply.setMessage('Hello ' + call.request.getName());
+  callback(null, reply);
 }
 
 /**
@@ -49,7 +51,7 @@
  */
 function main() {
   var server = new grpc.Server();
-  server.addProtoService(hello_proto.Greeter.service, {sayHello: sayHello});
+  server.addService(services.GreeterService, {sayHello: sayHello});
   server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
   server.start();
 }
diff --git a/examples/node/static_codegen/helloworld_grpc_pb.js b/examples/node/static_codegen/helloworld_grpc_pb.js
new file mode 100644
index 0000000..846f8b6
--- /dev/null
+++ b/examples/node/static_codegen/helloworld_grpc_pb.js
@@ -0,0 +1,44 @@
+// GENERATED CODE -- DO NOT EDIT!
+
+'use strict';
+var grpc = require('grpc');
+var helloworld_pb = require('./helloworld_pb.js');
+
+function serialize_HelloReply(arg) {
+  if (!(arg instanceof helloworld_pb.HelloReply)) {
+    throw new Error('Expected argument of type HelloReply');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_HelloReply(buffer_arg) {
+  return helloworld_pb.HelloReply.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+function serialize_HelloRequest(arg) {
+  if (!(arg instanceof helloworld_pb.HelloRequest)) {
+    throw new Error('Expected argument of type HelloRequest');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_HelloRequest(buffer_arg) {
+  return helloworld_pb.HelloRequest.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+
+var GreeterService = exports.GreeterService = {
+  sayHello: {
+    path: '/helloworld.Greeter/SayHello',
+    requestStream: false,
+    responseStream: false,
+    requestType: helloworld_pb.HelloRequest,
+    responseType: helloworld_pb.HelloReply,
+    requestSerialize: serialize_HelloRequest,
+    requestDeserialize: deserialize_HelloRequest,
+    responseSerialize: serialize_HelloReply,
+    responseDeserialize: deserialize_HelloReply,
+  },
+};
+
+exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService);
diff --git a/examples/node/static_codegen/helloworld_pb.js b/examples/node/static_codegen/helloworld_pb.js
new file mode 100644
index 0000000..6405bd9
--- /dev/null
+++ b/examples/node/static_codegen/helloworld_pb.js
@@ -0,0 +1,332 @@
+/**
+ * @fileoverview
+ * @enhanceable
+ * @public
+ */
+// GENERATED CODE -- DO NOT EDIT!
+
+var jspb = require('google-protobuf');
+var goog = jspb;
+var global = Function('return this')();
+
+goog.exportSymbol('proto.helloworld.HelloReply', null, global);
+goog.exportSymbol('proto.helloworld.HelloRequest', null, global);
+
+/**
+ * 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.helloworld.HelloRequest = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.helloworld.HelloRequest, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.helloworld.HelloRequest.displayName = 'proto.helloworld.HelloRequest';
+}
+
+
+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.helloworld.HelloRequest.prototype.toObject = function(opt_includeInstance) {
+  return proto.helloworld.HelloRequest.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.helloworld.HelloRequest} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.helloworld.HelloRequest.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    name: msg.getName()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.helloworld.HelloRequest}
+ */
+proto.helloworld.HelloRequest.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.helloworld.HelloRequest;
+  return proto.helloworld.HelloRequest.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.helloworld.HelloRequest} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.helloworld.HelloRequest}
+ */
+proto.helloworld.HelloRequest.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setName(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.helloworld.HelloRequest} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.helloworld.HelloRequest.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.helloworld.HelloRequest.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.helloworld.HelloRequest.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getName();
+  if (f.length > 0) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.helloworld.HelloRequest} The clone.
+ */
+proto.helloworld.HelloRequest.prototype.cloneMessage = function() {
+  return /** @type {!proto.helloworld.HelloRequest} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional string name = 1;
+ * @return {string}
+ */
+proto.helloworld.HelloRequest.prototype.getName = function() {
+  return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, ""));
+};
+
+
+/** @param {string} value  */
+proto.helloworld.HelloRequest.prototype.setName = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+
+/**
+ * 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.helloworld.HelloReply = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.helloworld.HelloReply, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.helloworld.HelloReply.displayName = 'proto.helloworld.HelloReply';
+}
+
+
+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.helloworld.HelloReply.prototype.toObject = function(opt_includeInstance) {
+  return proto.helloworld.HelloReply.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.helloworld.HelloReply} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.helloworld.HelloReply.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    message: msg.getMessage()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.helloworld.HelloReply}
+ */
+proto.helloworld.HelloReply.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.helloworld.HelloReply;
+  return proto.helloworld.HelloReply.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.helloworld.HelloReply} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.helloworld.HelloReply}
+ */
+proto.helloworld.HelloReply.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setMessage(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.helloworld.HelloReply} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.helloworld.HelloReply.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.helloworld.HelloReply.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.helloworld.HelloReply.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getMessage();
+  if (f.length > 0) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.helloworld.HelloReply} The clone.
+ */
+proto.helloworld.HelloReply.prototype.cloneMessage = function() {
+  return /** @type {!proto.helloworld.HelloReply} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional string message = 1;
+ * @return {string}
+ */
+proto.helloworld.HelloReply.prototype.getMessage = function() {
+  return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, ""));
+};
+
+
+/** @param {string} value  */
+proto.helloworld.HelloReply.prototype.setMessage = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+goog.object.extend(exports, proto.helloworld);
diff --git a/examples/node/route_guide/README.md b/examples/node/static_codegen/route_guide/README.md
similarity index 100%
rename from examples/node/route_guide/README.md
rename to examples/node/static_codegen/route_guide/README.md
diff --git a/examples/node/route_guide/route_guide_client.js b/examples/node/static_codegen/route_guide/route_guide_client.js
similarity index 66%
copy from examples/node/route_guide/route_guide_client.js
copy to examples/node/static_codegen/route_guide/route_guide_client.js
index fd05a59..ecde786 100644
--- a/examples/node/route_guide/route_guide_client.js
+++ b/examples/node/static_codegen/route_guide/route_guide_client.js
@@ -31,7 +31,8 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../../protos/route_guide.proto';
+var messages = require('./route_guide_pb');
+var services = require('./route_guide_grpc_pb');
 
 var async = require('async');
 var fs = require('fs');
@@ -39,9 +40,9 @@
 var path = require('path');
 var _ = require('lodash');
 var grpc = require('grpc');
-var routeguide = grpc.load(PROTO_PATH).routeguide;
-var client = new routeguide.RouteGuide('localhost:50051',
-                                       grpc.credentials.createInsecure());
+
+var client = new services.RouteGuideClient('localhost:50051',
+                                           grpc.credentials.createInsecure());
 
 var COORD_FACTOR = 1e7;
 
@@ -56,25 +57,23 @@
     if (error) {
       callback(error);
     }
-    if (feature.name === '') {
+    var latitude = feature.getLocation().getLatitude();
+    var longitude = feature.getLocation().getLongitude();
+    if (feature.getName() === '') {
       console.log('Found no feature at ' +
-          feature.location.latitude/COORD_FACTOR + ', ' +
-          feature.location.longitude/COORD_FACTOR);
+          latitude/COORD_FACTOR + ', ' + longitude/COORD_FACTOR);
     } else {
-      console.log('Found feature called "' + feature.name + '" at ' +
-          feature.location.latitude/COORD_FACTOR + ', ' +
-          feature.location.longitude/COORD_FACTOR);
+      console.log('Found feature called "' + feature.getName() + '" at ' +
+          latitude/COORD_FACTOR + ', ' + longitude/COORD_FACTOR);
     }
     next();
   }
-  var point1 = {
-    latitude: 409146138,
-    longitude: -746188906
-  };
-  var point2 = {
-    latitude: 0,
-    longitude: 0
-  };
+  var point1 = new messages.Point();
+  point1.setLatitude(409146138);
+  point1.setLongitude(-746188906);
+  var point2 = new messages.Point();
+  point2.setLatitude(0);
+  point2.setLongitude(0);
   client.getFeature(point1, featureCallback);
   client.getFeature(point2, featureCallback);
 }
@@ -86,22 +85,21 @@
  * @param {function} callback Called when this demo is complete
  */
 function runListFeatures(callback) {
-  var rectangle = {
-    lo: {
-      latitude: 400000000,
-      longitude: -750000000
-    },
-    hi: {
-      latitude: 420000000,
-      longitude: -730000000
-    }
-  };
+  var rect = new messages.Rectangle();
+  var lo = new messages.Point();
+  lo.setLatitude(400000000);
+  lo.setLongitude(-750000000);
+  rect.setLo(lo);
+  var hi = new messages.Point();
+  hi.setLatitude(420000000);
+  hi.setLongitude(-730000000);
+  rect.setHi(hi);
   console.log('Looking for features between 40, -75 and 42, -73');
-  var call = client.listFeatures(rectangle);
+  var call = client.listFeatures(rect);
   call.on('data', function(feature) {
-      console.log('Found feature called "' + feature.name + '" at ' +
-          feature.location.latitude/COORD_FACTOR + ', ' +
-          feature.location.longitude/COORD_FACTOR);
+      console.log('Found feature called "' + feature.getName() + '" at ' +
+          feature.getLocation().getLatitude()/COORD_FACTOR + ', ' +
+          feature.getLocation().getLongitude()/COORD_FACTOR);
   });
   call.on('end', callback);
 }
@@ -118,46 +116,50 @@
   });
   fs.readFile(path.resolve(argv.db_path), function(err, data) {
     if (err) callback(err);
-    var feature_list = JSON.parse(data);
+    // Transform the loaded features to Feature objects
+    var feature_list = _.map(JSON.parse(data), function(value) {
+      var feature = new messages.Feature();
+      feature.setName(value.name);
+      var location = new messages.Point();
+      location.setLatitude(value.location.latitude);
+      location.setLongitude(value.location.longitude);
+      feature.setLocation(location);
+      return feature;
+    });
 
     var num_points = 10;
     var call = client.recordRoute(function(error, stats) {
       if (error) {
         callback(error);
       }
-      console.log('Finished trip with', stats.point_count, 'points');
-      console.log('Passed', stats.feature_count, 'features');
-      console.log('Travelled', stats.distance, 'meters');
-      console.log('It took', stats.elapsed_time, 'seconds');
+      console.log('Finished trip with', stats.getPointCount(), 'points');
+      console.log('Passed', stats.getFeatureCount(), 'features');
+      console.log('Travelled', stats.getDistance(), 'meters');
+      console.log('It took', stats.getElapsedTime(), 'seconds');
       callback();
     });
     /**
      * Constructs a function that asynchronously sends the given point and then
      * delays sending its callback
-     * @param {number} lat The latitude to send
-     * @param {number} lng The longitude to send
+     * @param {messages.Point} location The point to send
      * @return {function(function)} The function that sends the point
      */
-    function pointSender(lat, lng) {
+    function pointSender(location) {
       /**
        * Sends the point, then calls the callback after a delay
        * @param {function} callback Called when complete
        */
       return function(callback) {
-        console.log('Visiting point ' + lat/COORD_FACTOR + ', ' +
-            lng/COORD_FACTOR);
-        call.write({
-          latitude: lat,
-          longitude: lng
-        });
+        console.log('Visiting point ' + location.getLatitude()/COORD_FACTOR +
+            ', ' + location.getLongitude()/COORD_FACTOR);
+        call.write(location);
         _.delay(callback, _.random(500, 1500));
       };
     }
     var point_senders = [];
     for (var i = 0; i < num_points; i++) {
       var rand_point = feature_list[_.random(0, feature_list.length - 1)];
-      point_senders[i] = pointSender(rand_point.location.latitude,
-                                     rand_point.location.longitude);
+      point_senders[i] = pointSender(rand_point.getLocation());
     }
     async.series(point_senders, function() {
       call.end();
@@ -173,8 +175,9 @@
 function runRouteChat(callback) {
   var call = client.routeChat();
   call.on('data', function(note) {
-    console.log('Got message "' + note.message + '" at ' +
-        note.location.latitude + ', ' + note.location.longitude);
+    console.log('Got message "' + note.getMessage() + '" at ' +
+        note.getLocation().getLatitude() + ', ' +
+        note.getLocation().getLongitude());
   });
 
   call.on('end', callback);
@@ -208,7 +211,13 @@
     var note = notes[i];
     console.log('Sending message "' + note.message + '" at ' +
         note.location.latitude + ', ' + note.location.longitude);
-    call.write(note);
+    var noteMsg = new messages.RouteNote();
+    noteMsg.setMessage(note.message);
+    var location = new messages.Point();
+    location.setLatitude(note.location.latitude);
+    location.setLongitude(note.location.longitude);
+    noteMsg.setLocation(location);
+    call.write(noteMsg);
   }
   call.end();
 }
diff --git a/examples/node/route_guide/route_guide_db.json b/examples/node/static_codegen/route_guide/route_guide_db.json
similarity index 100%
rename from examples/node/route_guide/route_guide_db.json
rename to examples/node/static_codegen/route_guide/route_guide_db.json
diff --git a/examples/node/static_codegen/route_guide/route_guide_grpc_pb.js b/examples/node/static_codegen/route_guide/route_guide_grpc_pb.js
new file mode 100644
index 0000000..1dd7133
--- /dev/null
+++ b/examples/node/static_codegen/route_guide/route_guide_grpc_pb.js
@@ -0,0 +1,110 @@
+// GENERATED CODE -- DO NOT EDIT!
+
+'use strict';
+var grpc = require('grpc');
+var route_guide_pb = require('./route_guide_pb.js');
+
+function serialize_Feature(arg) {
+  if (!(arg instanceof route_guide_pb.Feature)) {
+    throw new Error('Expected argument of type Feature');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_Feature(buffer_arg) {
+  return route_guide_pb.Feature.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+function serialize_Point(arg) {
+  if (!(arg instanceof route_guide_pb.Point)) {
+    throw new Error('Expected argument of type Point');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_Point(buffer_arg) {
+  return route_guide_pb.Point.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+function serialize_Rectangle(arg) {
+  if (!(arg instanceof route_guide_pb.Rectangle)) {
+    throw new Error('Expected argument of type Rectangle');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_Rectangle(buffer_arg) {
+  return route_guide_pb.Rectangle.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+function serialize_RouteNote(arg) {
+  if (!(arg instanceof route_guide_pb.RouteNote)) {
+    throw new Error('Expected argument of type RouteNote');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_RouteNote(buffer_arg) {
+  return route_guide_pb.RouteNote.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+function serialize_RouteSummary(arg) {
+  if (!(arg instanceof route_guide_pb.RouteSummary)) {
+    throw new Error('Expected argument of type RouteSummary');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_RouteSummary(buffer_arg) {
+  return route_guide_pb.RouteSummary.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+
+var RouteGuideService = exports.RouteGuideService = {
+  getFeature: {
+    path: '/routeguide.RouteGuide/GetFeature',
+    requestStream: false,
+    responseStream: false,
+    requestType: route_guide_pb.Point,
+    responseType: route_guide_pb.Feature,
+    requestSerialize: serialize_Point,
+    requestDeserialize: deserialize_Point,
+    responseSerialize: serialize_Feature,
+    responseDeserialize: deserialize_Feature,
+  },
+  listFeatures: {
+    path: '/routeguide.RouteGuide/ListFeatures',
+    requestStream: false,
+    responseStream: true,
+    requestType: route_guide_pb.Rectangle,
+    responseType: route_guide_pb.Feature,
+    requestSerialize: serialize_Rectangle,
+    requestDeserialize: deserialize_Rectangle,
+    responseSerialize: serialize_Feature,
+    responseDeserialize: deserialize_Feature,
+  },
+  recordRoute: {
+    path: '/routeguide.RouteGuide/RecordRoute',
+    requestStream: true,
+    responseStream: false,
+    requestType: route_guide_pb.Point,
+    responseType: route_guide_pb.RouteSummary,
+    requestSerialize: serialize_Point,
+    requestDeserialize: deserialize_Point,
+    responseSerialize: serialize_RouteSummary,
+    responseDeserialize: deserialize_RouteSummary,
+  },
+  routeChat: {
+    path: '/routeguide.RouteGuide/RouteChat',
+    requestStream: true,
+    responseStream: true,
+    requestType: route_guide_pb.RouteNote,
+    responseType: route_guide_pb.RouteNote,
+    requestSerialize: serialize_RouteNote,
+    requestDeserialize: deserialize_RouteNote,
+    responseSerialize: serialize_RouteNote,
+    responseDeserialize: deserialize_RouteNote,
+  },
+};
+
+exports.RouteGuideClient = grpc.makeGenericClientConstructor(RouteGuideService);
diff --git a/examples/node/static_codegen/route_guide/route_guide_pb.js b/examples/node/static_codegen/route_guide/route_guide_pb.js
new file mode 100644
index 0000000..f604cd6
--- /dev/null
+++ b/examples/node/static_codegen/route_guide/route_guide_pb.js
@@ -0,0 +1,1033 @@
+/**
+ * @fileoverview
+ * @enhanceable
+ * @public
+ */
+// GENERATED CODE -- DO NOT EDIT!
+
+var jspb = require('google-protobuf');
+var goog = jspb;
+var global = Function('return this')();
+
+goog.exportSymbol('proto.routeguide.Feature', null, global);
+goog.exportSymbol('proto.routeguide.Point', null, global);
+goog.exportSymbol('proto.routeguide.Rectangle', null, global);
+goog.exportSymbol('proto.routeguide.RouteNote', null, global);
+goog.exportSymbol('proto.routeguide.RouteSummary', null, global);
+
+/**
+ * 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.routeguide.Point = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.routeguide.Point, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.routeguide.Point.displayName = 'proto.routeguide.Point';
+}
+
+
+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.routeguide.Point.prototype.toObject = function(opt_includeInstance) {
+  return proto.routeguide.Point.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.routeguide.Point} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.routeguide.Point.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    latitude: msg.getLatitude(),
+    longitude: msg.getLongitude()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.routeguide.Point}
+ */
+proto.routeguide.Point.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.routeguide.Point;
+  return proto.routeguide.Point.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.routeguide.Point} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.routeguide.Point}
+ */
+proto.routeguide.Point.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {number} */ (reader.readInt32());
+      msg.setLatitude(value);
+      break;
+    case 2:
+      var value = /** @type {number} */ (reader.readInt32());
+      msg.setLongitude(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.routeguide.Point} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.Point.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.routeguide.Point.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.Point.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getLatitude();
+  if (f !== 0) {
+    writer.writeInt32(
+      1,
+      f
+    );
+  }
+  f = this.getLongitude();
+  if (f !== 0) {
+    writer.writeInt32(
+      2,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.routeguide.Point} The clone.
+ */
+proto.routeguide.Point.prototype.cloneMessage = function() {
+  return /** @type {!proto.routeguide.Point} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional int32 latitude = 1;
+ * @return {number}
+ */
+proto.routeguide.Point.prototype.getLatitude = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
+};
+
+
+/** @param {number} value  */
+proto.routeguide.Point.prototype.setLatitude = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * optional int32 longitude = 2;
+ * @return {number}
+ */
+proto.routeguide.Point.prototype.getLongitude = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0));
+};
+
+
+/** @param {number} value  */
+proto.routeguide.Point.prototype.setLongitude = function(value) {
+  jspb.Message.setField(this, 2, value);
+};
+
+
+
+/**
+ * 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.routeguide.Rectangle = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.routeguide.Rectangle, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.routeguide.Rectangle.displayName = 'proto.routeguide.Rectangle';
+}
+
+
+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.routeguide.Rectangle.prototype.toObject = function(opt_includeInstance) {
+  return proto.routeguide.Rectangle.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.routeguide.Rectangle} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.routeguide.Rectangle.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    lo: (f = msg.getLo()) && proto.routeguide.Point.toObject(includeInstance, f),
+    hi: (f = msg.getHi()) && proto.routeguide.Point.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.routeguide.Rectangle}
+ */
+proto.routeguide.Rectangle.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.routeguide.Rectangle;
+  return proto.routeguide.Rectangle.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.routeguide.Rectangle} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.routeguide.Rectangle}
+ */
+proto.routeguide.Rectangle.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = new proto.routeguide.Point;
+      reader.readMessage(value,proto.routeguide.Point.deserializeBinaryFromReader);
+      msg.setLo(value);
+      break;
+    case 2:
+      var value = new proto.routeguide.Point;
+      reader.readMessage(value,proto.routeguide.Point.deserializeBinaryFromReader);
+      msg.setHi(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.routeguide.Rectangle} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.Rectangle.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.routeguide.Rectangle.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.Rectangle.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getLo();
+  if (f != null) {
+    writer.writeMessage(
+      1,
+      f,
+      proto.routeguide.Point.serializeBinaryToWriter
+    );
+  }
+  f = this.getHi();
+  if (f != null) {
+    writer.writeMessage(
+      2,
+      f,
+      proto.routeguide.Point.serializeBinaryToWriter
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.routeguide.Rectangle} The clone.
+ */
+proto.routeguide.Rectangle.prototype.cloneMessage = function() {
+  return /** @type {!proto.routeguide.Rectangle} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional Point lo = 1;
+ * @return {proto.routeguide.Point}
+ */
+proto.routeguide.Rectangle.prototype.getLo = function() {
+  return /** @type{proto.routeguide.Point} */ (
+    jspb.Message.getWrapperField(this, proto.routeguide.Point, 1));
+};
+
+
+/** @param {proto.routeguide.Point|undefined} value  */
+proto.routeguide.Rectangle.prototype.setLo = function(value) {
+  jspb.Message.setWrapperField(this, 1, value);
+};
+
+
+proto.routeguide.Rectangle.prototype.clearLo = function() {
+  this.setLo(undefined);
+};
+
+
+/**
+ * optional Point hi = 2;
+ * @return {proto.routeguide.Point}
+ */
+proto.routeguide.Rectangle.prototype.getHi = function() {
+  return /** @type{proto.routeguide.Point} */ (
+    jspb.Message.getWrapperField(this, proto.routeguide.Point, 2));
+};
+
+
+/** @param {proto.routeguide.Point|undefined} value  */
+proto.routeguide.Rectangle.prototype.setHi = function(value) {
+  jspb.Message.setWrapperField(this, 2, value);
+};
+
+
+proto.routeguide.Rectangle.prototype.clearHi = function() {
+  this.setHi(undefined);
+};
+
+
+
+/**
+ * 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.routeguide.Feature = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.routeguide.Feature, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.routeguide.Feature.displayName = 'proto.routeguide.Feature';
+}
+
+
+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.routeguide.Feature.prototype.toObject = function(opt_includeInstance) {
+  return proto.routeguide.Feature.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.routeguide.Feature} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.routeguide.Feature.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    name: msg.getName(),
+    location: (f = msg.getLocation()) && proto.routeguide.Point.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.routeguide.Feature}
+ */
+proto.routeguide.Feature.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.routeguide.Feature;
+  return proto.routeguide.Feature.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.routeguide.Feature} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.routeguide.Feature}
+ */
+proto.routeguide.Feature.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setName(value);
+      break;
+    case 2:
+      var value = new proto.routeguide.Point;
+      reader.readMessage(value,proto.routeguide.Point.deserializeBinaryFromReader);
+      msg.setLocation(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.routeguide.Feature} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.Feature.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.routeguide.Feature.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.Feature.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getName();
+  if (f.length > 0) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+  f = this.getLocation();
+  if (f != null) {
+    writer.writeMessage(
+      2,
+      f,
+      proto.routeguide.Point.serializeBinaryToWriter
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.routeguide.Feature} The clone.
+ */
+proto.routeguide.Feature.prototype.cloneMessage = function() {
+  return /** @type {!proto.routeguide.Feature} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional string name = 1;
+ * @return {string}
+ */
+proto.routeguide.Feature.prototype.getName = function() {
+  return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, ""));
+};
+
+
+/** @param {string} value  */
+proto.routeguide.Feature.prototype.setName = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * optional Point location = 2;
+ * @return {proto.routeguide.Point}
+ */
+proto.routeguide.Feature.prototype.getLocation = function() {
+  return /** @type{proto.routeguide.Point} */ (
+    jspb.Message.getWrapperField(this, proto.routeguide.Point, 2));
+};
+
+
+/** @param {proto.routeguide.Point|undefined} value  */
+proto.routeguide.Feature.prototype.setLocation = function(value) {
+  jspb.Message.setWrapperField(this, 2, value);
+};
+
+
+proto.routeguide.Feature.prototype.clearLocation = function() {
+  this.setLocation(undefined);
+};
+
+
+
+/**
+ * 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.routeguide.RouteNote = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.routeguide.RouteNote, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.routeguide.RouteNote.displayName = 'proto.routeguide.RouteNote';
+}
+
+
+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.routeguide.RouteNote.prototype.toObject = function(opt_includeInstance) {
+  return proto.routeguide.RouteNote.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.routeguide.RouteNote} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.routeguide.RouteNote.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    location: (f = msg.getLocation()) && proto.routeguide.Point.toObject(includeInstance, f),
+    message: msg.getMessage()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.routeguide.RouteNote}
+ */
+proto.routeguide.RouteNote.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.routeguide.RouteNote;
+  return proto.routeguide.RouteNote.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.routeguide.RouteNote} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.routeguide.RouteNote}
+ */
+proto.routeguide.RouteNote.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = new proto.routeguide.Point;
+      reader.readMessage(value,proto.routeguide.Point.deserializeBinaryFromReader);
+      msg.setLocation(value);
+      break;
+    case 2:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setMessage(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.routeguide.RouteNote} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.RouteNote.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.routeguide.RouteNote.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.RouteNote.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getLocation();
+  if (f != null) {
+    writer.writeMessage(
+      1,
+      f,
+      proto.routeguide.Point.serializeBinaryToWriter
+    );
+  }
+  f = this.getMessage();
+  if (f.length > 0) {
+    writer.writeString(
+      2,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.routeguide.RouteNote} The clone.
+ */
+proto.routeguide.RouteNote.prototype.cloneMessage = function() {
+  return /** @type {!proto.routeguide.RouteNote} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional Point location = 1;
+ * @return {proto.routeguide.Point}
+ */
+proto.routeguide.RouteNote.prototype.getLocation = function() {
+  return /** @type{proto.routeguide.Point} */ (
+    jspb.Message.getWrapperField(this, proto.routeguide.Point, 1));
+};
+
+
+/** @param {proto.routeguide.Point|undefined} value  */
+proto.routeguide.RouteNote.prototype.setLocation = function(value) {
+  jspb.Message.setWrapperField(this, 1, value);
+};
+
+
+proto.routeguide.RouteNote.prototype.clearLocation = function() {
+  this.setLocation(undefined);
+};
+
+
+/**
+ * optional string message = 2;
+ * @return {string}
+ */
+proto.routeguide.RouteNote.prototype.getMessage = function() {
+  return /** @type {string} */ (jspb.Message.getFieldProto3(this, 2, ""));
+};
+
+
+/** @param {string} value  */
+proto.routeguide.RouteNote.prototype.setMessage = function(value) {
+  jspb.Message.setField(this, 2, value);
+};
+
+
+
+/**
+ * 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.routeguide.RouteSummary = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.routeguide.RouteSummary, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.routeguide.RouteSummary.displayName = 'proto.routeguide.RouteSummary';
+}
+
+
+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.routeguide.RouteSummary.prototype.toObject = function(opt_includeInstance) {
+  return proto.routeguide.RouteSummary.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.routeguide.RouteSummary} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.routeguide.RouteSummary.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    pointCount: msg.getPointCount(),
+    featureCount: msg.getFeatureCount(),
+    distance: msg.getDistance(),
+    elapsedTime: msg.getElapsedTime()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.routeguide.RouteSummary}
+ */
+proto.routeguide.RouteSummary.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.routeguide.RouteSummary;
+  return proto.routeguide.RouteSummary.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.routeguide.RouteSummary} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.routeguide.RouteSummary}
+ */
+proto.routeguide.RouteSummary.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {number} */ (reader.readInt32());
+      msg.setPointCount(value);
+      break;
+    case 2:
+      var value = /** @type {number} */ (reader.readInt32());
+      msg.setFeatureCount(value);
+      break;
+    case 3:
+      var value = /** @type {number} */ (reader.readInt32());
+      msg.setDistance(value);
+      break;
+    case 4:
+      var value = /** @type {number} */ (reader.readInt32());
+      msg.setElapsedTime(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.routeguide.RouteSummary} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.RouteSummary.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.routeguide.RouteSummary.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.routeguide.RouteSummary.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getPointCount();
+  if (f !== 0) {
+    writer.writeInt32(
+      1,
+      f
+    );
+  }
+  f = this.getFeatureCount();
+  if (f !== 0) {
+    writer.writeInt32(
+      2,
+      f
+    );
+  }
+  f = this.getDistance();
+  if (f !== 0) {
+    writer.writeInt32(
+      3,
+      f
+    );
+  }
+  f = this.getElapsedTime();
+  if (f !== 0) {
+    writer.writeInt32(
+      4,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.routeguide.RouteSummary} The clone.
+ */
+proto.routeguide.RouteSummary.prototype.cloneMessage = function() {
+  return /** @type {!proto.routeguide.RouteSummary} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional int32 point_count = 1;
+ * @return {number}
+ */
+proto.routeguide.RouteSummary.prototype.getPointCount = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
+};
+
+
+/** @param {number} value  */
+proto.routeguide.RouteSummary.prototype.setPointCount = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * optional int32 feature_count = 2;
+ * @return {number}
+ */
+proto.routeguide.RouteSummary.prototype.getFeatureCount = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0));
+};
+
+
+/** @param {number} value  */
+proto.routeguide.RouteSummary.prototype.setFeatureCount = function(value) {
+  jspb.Message.setField(this, 2, value);
+};
+
+
+/**
+ * optional int32 distance = 3;
+ * @return {number}
+ */
+proto.routeguide.RouteSummary.prototype.getDistance = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 3, 0));
+};
+
+
+/** @param {number} value  */
+proto.routeguide.RouteSummary.prototype.setDistance = function(value) {
+  jspb.Message.setField(this, 3, value);
+};
+
+
+/**
+ * optional int32 elapsed_time = 4;
+ * @return {number}
+ */
+proto.routeguide.RouteSummary.prototype.getElapsedTime = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 4, 0));
+};
+
+
+/** @param {number} value  */
+proto.routeguide.RouteSummary.prototype.setElapsedTime = function(value) {
+  jspb.Message.setField(this, 4, value);
+};
+
+
+goog.object.extend(exports, proto.routeguide);
diff --git a/examples/node/route_guide/route_guide_server.js b/examples/node/static_codegen/route_guide/route_guide_server.js
similarity index 77%
copy from examples/node/route_guide/route_guide_server.js
copy to examples/node/static_codegen/route_guide/route_guide_server.js
index 6c01fac..53628fb 100644
--- a/examples/node/route_guide/route_guide_server.js
+++ b/examples/node/static_codegen/route_guide/route_guide_server.js
@@ -31,14 +31,14 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../../protos/route_guide.proto';
+var messages = require('./route_guide_pb');
+var services = require('./route_guide_grpc_pb');
 
 var fs = require('fs');
 var parseArgs = require('minimist');
 var path = require('path');
 var _ = require('lodash');
 var grpc = require('grpc');
-var routeguide = grpc.load(PROTO_PATH).routeguide;
 
 var COORD_FACTOR = 1e7;
 
@@ -65,16 +65,15 @@
   // Check if there is already a feature object for the given point
   for (var i = 0; i < feature_list.length; i++) {
     feature = feature_list[i];
-    if (feature.location.latitude === point.latitude &&
-        feature.location.longitude === point.longitude) {
+    if (feature.getLocation().getLatitude() === point.getLatitude() &&
+        feature.getLocation().getLongitude() === point.getLongitude()) {
       return feature;
     }
   }
   var name = '';
-  feature = {
-    name: name,
-    location: point
-  };
+  feature = new messages.Feature();
+  feature.setName(name);
+  feature.setLocation(point);
   return feature;
 }
 
@@ -95,21 +94,21 @@
  *     request property for the request value.
  */
 function listFeatures(call) {
-  var lo = call.request.lo;
-  var hi = call.request.hi;
-  var left = _.min([lo.longitude, hi.longitude]);
-  var right = _.max([lo.longitude, hi.longitude]);
-  var top = _.max([lo.latitude, hi.latitude]);
-  var bottom = _.min([lo.latitude, hi.latitude]);
+  var lo = call.request.getLo();
+  var hi = call.request.getHi();
+  var left = _.min([lo.getLongitude(), hi.getLongitude()]);
+  var right = _.max([lo.getLongitude(), hi.getLongitude()]);
+  var top = _.max([lo.getLatitude(), hi.getLatitude()]);
+  var bottom = _.min([lo.getLatitude(), hi.getLatitude()]);
   // For each feature, check if it is in the given bounding box
   _.each(feature_list, function(feature) {
-    if (feature.name === '') {
+    if (feature.getName() === '') {
       return;
     }
-    if (feature.location.longitude >= left &&
-        feature.location.longitude <= right &&
-        feature.location.latitude >= bottom &&
-        feature.location.latitude <= top) {
+    if (feature.getLocation().getLongitude() >= left &&
+        feature.getLocation().getLongitude() <= right &&
+        feature.getLocation().getLatitude() >= bottom &&
+        feature.getLocation().getLatitude() <= top) {
       call.write(feature);
     }
   });
@@ -127,10 +126,10 @@
   function toRadians(num) {
     return num * Math.PI / 180;
   }
-  var lat1 = start.latitude / COORD_FACTOR;
-  var lat2 = end.latitude / COORD_FACTOR;
-  var lon1 = start.longitude / COORD_FACTOR;
-  var lon2 = end.longitude / COORD_FACTOR;
+  var lat1 = start.getLatitude() / COORD_FACTOR;
+  var lat2 = end.getLatitude() / COORD_FACTOR;
+  var lon1 = start.getLongitude() / COORD_FACTOR;
+  var lon2 = end.getLongitude() / COORD_FACTOR;
   var R = 6371000; // metres
   var φ1 = toRadians(lat1);
   var φ2 = toRadians(lat2);
@@ -173,14 +172,14 @@
     previous = point;
   });
   call.on('end', function() {
-    callback(null, {
-      point_count: point_count,
-      feature_count: feature_count,
-      // Cast the distance to an integer
-      distance: distance|0,
-      // End the timer
-      elapsed_time: process.hrtime(start_time)[0]
-    });
+    var summary = new messages.RouteSummary();
+    summary.setPointCount(point_count);
+    summary.setFeatureCount(feature_count);
+    // Cast the distance to an integer
+    summary.setDistance(distance|0);
+    // End the timer
+    summary.setElapsedTime(process.hrtime(start_time)[0]);
+    callback(null, summary);
   });
 }
 
@@ -192,7 +191,7 @@
  * @return {string} The key for an object
  */
 function pointKey(point) {
-  return point.latitude + ' ' + point.longitude;
+  return point.getLatitude() + ' ' + point.getLongitude();
 }
 
 /**
@@ -202,7 +201,7 @@
  */
 function routeChat(call) {
   call.on('data', function(note) {
-    var key = pointKey(note.location);
+    var key = pointKey(note.getLocation());
     /* For each note sent, respond with all previous notes that correspond to
      * the same point */
     if (route_notes.hasOwnProperty(key)) {
@@ -213,7 +212,7 @@
       route_notes[key] = [];
     }
     // Then add the new note to the list
-    route_notes[key].push(JSON.parse(JSON.stringify(note)));
+    route_notes[key].push(note);
   });
   call.on('end', function() {
     call.end();
@@ -227,7 +226,7 @@
  */
 function getServer() {
   var server = new grpc.Server();
-  server.addProtoService(routeguide.RouteGuide.service, {
+  server.addService(services.RouteGuideService, {
     getFeature: getFeature,
     listFeatures: listFeatures,
     recordRoute: recordRoute,
@@ -245,7 +244,16 @@
   });
   fs.readFile(path.resolve(argv.db_path), function(err, data) {
     if (err) throw err;
-    feature_list = JSON.parse(data);
+    // Transform the loaded features to Feature objects
+    feature_list = _.map(JSON.parse(data), function(value) {
+      var feature = new messages.Feature();
+      feature.setName(value.name);
+      var location = new messages.Point();
+      location.setLatitude(value.location.latitude);
+      location.setLongitude(value.location.longitude);
+      feature.setLocation(location);
+      return feature;
+    });
     routeServer.start();
   });
 }