gRPC

How to create a server and a client, and communicate between them.

Key takeaways

GrpcService gRPC service component.
GrpcClient gRPC client component.
summator.proto Proto file containing messages and services.
Protoc Proto file compiler.

Introduction

In this tutorial, you will learn how to create a gRPC client and server by using the Pip.Services' gRPC module. We will start with an explanation of how to install this module and a brief description of the example used. Next, we will see how to create a gRPC server and client. Lastly, we will have a section containing the complete code for this project.

Pre-requisites

In order to create a gRPC server and client, we need to install the grpc module first. The command to do this is:

npm install pip-services4-grpc-node --save
Not available
Not available
Not available
!pip install pip_services4_http
Not available

A brief overview of the example

Our example consists of two programs: a service and a client, which communicate between them via the gRPC protocol. The process is as follows

  1. The client creates a request to add two numbers that is translated into a proto request via the gRPC stub and sent to the service.
  2. The service receives these two numbers, translates the proto request via the gRPC server, and calls a function named sum. This function is available from the Summator program.
  3. Once the result is on the server, it is translated into a proto response and sent to the client.
  4. The client receives the result, and translates and prints it.

The figure below summarizes this procedure.

figure 1

In order to communicate via the gRPC protocol, the client uses a gRPC stub and the service a gRPC server. Both are constructed based on the summator2.proto file, which contains descriptions of the input parameters, and the function used. These descriptions are transformed into two coded files via the protoc compiler.

These coded files are written in the languages of the service and client respectively. Their names are: summator2_pb2 and summator_pb2_grpc. Together, they contain all the necessary elements to create the gRPC server and the gRPC client.

Proto file

The proto file describes the communication contract between the client and the server. It is written in proto3, a language created by Google to describe gRPC communications.

Syntax

Our proto file will contain the following elements:

  1. Syntax: A command indicating that we are using proto3
  2. Number1: A message item describing the input to our function. In our case, we will define both values as floats.
  3. Number2: A message item describing the value returned by our method. In this example, we return the sum of the inputs as a float value.
  4. Summator: A service item describing our method.

The figure below summarizes this description.

figure 2

Compilation

A proto file can be compiled into files in different languages, such as Python, C++, Ruby, C#, Go, and Java. This is done by running the protocol buffer compiler protoc on the .proto file.

The compiler generates two files per language with the information on data types, stub and server.

In our case, both client and service are written in the same language. Thus, we generate a common set of files. Our command is:

npx grpc_tools_node_protoc  --js_out=import_style=commonjs,binary:./ --grpc_out=.  ./summator.proto

Not available
Not available
Not available
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. summator2.proto
Not available
Not available
Not available
Not available

And the generated files are:

  1. summator2_pb2: contains message classes
    a. Number1: describes the types of the input paramters
    b. Number2: describes the result’s type.
  2. summator2_pb2_grpc: contains server and client classes:
    a. SummatorServicer
    b. SummatorStub
Not available

Server

We create a server that communicates to clients via the gRPC protocol and connects to a library of functions, which in this example is represented by the Summator file.

The following sections explain these features in detail.

Summator file

In our example, we call a function named sum, which is available via the summator file. This function adds two given numbers and returns the result. Its code is as follows:

export class Calculations {
    public static sum(x: number, y: number): number {
        let z = x + y;
        return z;
    }
}

Not available
Not available
Not available
def sum(x,y):
  z = x + y
  return z
Not available

gRPC service

This is the component that communicates with the library of functions and sends the results to clients after receiving their requests.

Pre-requisites
GrpcService

First, we need to import the GrpcService class from the gRPC module. We can do this with the following command:

import { GrpcController } from "pip-services4-grpc-node";
Not available
Not available
Not available
from pip_services4_grpc.controllers import GrpcController
Not available
Proto compiler generated classes

We also need to import the two files previously generated by the protoc compiler.

let services = require('../summator_grpc_pb');
let messages = require('../summator_pb');

Not available
Not available
Not available
import summator_pb2
import summator_pb2_grpc
Not available
Library of functions

And the library with the function available from the server.

import { Calculations } from "./calculations";

Not available
Not available
Not available
import summator
Not available
Not available
Not available
Not available
ServicerContext

In Python, we also need to consider the ServicerContext from grpc.

from grpc import ServicerContext
Not available
Component generation

Now that we have imported all the necessary elements, we can create our gRPC service, which is a subclass of the GrpcService class. In it, we need to define the method that we are using via the _register_method() method. The following code shows how to do this.

export class MyGrpcController extends GrpcController {

    public constructor() {
        super(services.SummatorService);
    }

    private async sum(call: any): Promise<any> {
        let res = Calculations.sum(call.request.getValue1(), call.request.getValue2());

        let response = new messages.Number2();
        response.setValue(res);

        return response;
    }


    public register(): void {
        this.registerMethod(
            "sum",
            null,
            this.sum
        );
    }
}
Not available
Not available
Not available
class MyGrpcController(GrpcController, summator_pb2_grpc.SummatorServicer):

    def __init__(self):
        super().__init__('my_data_v1')

    def add_servicer_to_server(self, server):
        summator_pb2_grpc.add_SummatorServicer_to_server(self, server)

    def register(self):
        self._register_method("sum", None, self.__sum2)

    def __sum2(self, number: summator_pb2.Number1, context: ServicerContext):
        res = summator.sum(number.value1, number.value2)
        return summator_pb2.Number2(value1=res)
Not available

Next, we create an instance of the gRPC service and configure it with the connection parameters.

import { ConfigParams, References } from "pip-services4-components-nodes";

let controller = new MyGrpcController();
controller.configure(ConfigParams.fromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
));

controller.setReferences(new References());


Not available
Not available
Not available
class MyGrpcController(GrpcController, summator2_pb2_grpc.SummatorServicer):

    def __init__(self):
        super().__init__('my_data_v1')

    def add_servicer_to_server(self, server):
        summator2_pb2_grpc.add_SummatorServicer_to_server(self, server)

    def register(self):
        self._register_method("sum", None, self.__sum2)

    def __sum2(self, number: summator2_pb2.Number1, context: ServicerContext):
        res = summator.sum(number.value1, number.value2)
        return summator2_pb2.Number2(value1=res)
Not available
Running the service

Once we have our service ready, we launch it via the open() method.

await controller.open(null);

Not available
Not available
Not available
controller.open("123")
Not available

Our gRPC service is now listening from our computer (port 50051) and waiting for a client to send a request.

Client

The next step is to create a client, which will be used to call the sum() method available from the service, and obtain the corresponding result.

Pre-requisites

GrpcClient

In order to use this component, we need to import it first. The following command shows how to do this:

import { GrpcClient } from "pip-services4-grpc-node";
Not available
Not available
Not available
from pip_services4_grpc.clients import GrpcClient
Not available
Proto compiler generated classes

We also need to import the two files previously generated by the protoc compiler.

let services = require('../summator_grpc_pb');
let messages = require('../summator_pb');

Not available
Not available
Not available
import summator_pb2
import summator_pb2_grpc
Not available

Component generation

Once we have imported all the necessary files, we create a subclass of GrpcClient. In it, we define the get_data method, which calls the Sum method and returns the received result. The code is as follows:

export class MyGrpcClient extends GrpcClient {
    public constructor() {
        super(services.SummatorClient);
    }

    public async getData(correlationId: string, value1: number, value2: number): Promise<number> {
        let request = new messages.Number1();
        request.setValue1(value1);
        request.setValue2(value2);

        let res = await this.call<any>("sum", correlationId, request);

        return res.getValue();
    }
}
Not available
Not available
Not available
class MyGrpcClient(GrpcClient):
     def __init__(self):
        super().__init__(summator_pb2_grpc.SummatorStub, 'Summator')
        
     def get_data(self, context, value1, value2):
        number = summator_pb2.Number1(value1=value1, value2=value2)
        result = self._call("sum", None, number)
        return result,value
Not available

After defining our gRCP client, we create an instance of it and use the configure() method to define the connection parameters. In our example, we connect to a server using our machine via the default port 50051.

import { ConfigParams, References } from "pip-services4-components-node";

let client = new MyGrpcClient();
client.configure(ConfigParams.fromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
));

client.setReferences(new References());
Not available
Not available
Not available
from pip_services4_components.config import ConfigParams
from pip_services4_components.refer import References

client = MyGrpcClient()
client.configure(ConfigParams.from_tuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
))

client.set_references(References())
Not available

Finally, we connect to the server via the open() method.

await client.open(null);

Not available
Not available
Not available
client.open(None)
Not available

Consuming the service

The next step is to call the get_data() method and obtain the result. The following example shows how to use it to add five and three, which returns eight.

let result = await client.getData(null, 3, 5);  // Returns 8

Not available
Not available
Not available
result = client.get_data(None, 3,5)  # Returns 8
Not available

Final code

This section presents the complete code for the example, namely the server and client’s code, the proto file, the two compiler-generated files, and the library file.

Server

The code for the server is:

// Pre-requisites
let services = require('../summator_grpc_pb');
let messages = require('../summator_pb');

import { ConfigParams, Descriptor, References } from "pip-services4-components-node";
import { GrpcController } from "pip-services4-grpc-node";
import { Calculations } from "./calculations";

// gRPC controller
export class MyGrpcController extends GrpcController {

    public constructor() {
        super(services.SummatorService);
    }

    private async sum(call: any): Promise<any> {
        let res = Calculations.sum(call.request.getValue1(), call.request.getValue2());

        let response = new messages.Number2();
        response.setValue(res);

        return response;
    }


    public register(): void {
        this.registerMethod(
            "sum",
            null,
            this.sum
        );
    }
}
    
let controller = new MyGrpcController();
controller.configure(ConfigParams.fromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
));

controller.setReferences(new References());

await controller.open(null);
Not available
Not available
Not available
# Pre-requisites
import time
from grpc import ServicerContext
from pip_services4_grpc.controllers import GrpcController
from pip_services4_components.config import ConfigParams
from pip_services4_components.refer import References

import summator

import summator_pb2
import summator_pb2_grpc

# gRPC service


class MyGrpcController(GrpcController, summator_pb2_grpc.SummatorServicer):

    def __init__(self):
        super().__init__('my_data_v1')

    def add_servicer_to_server(self, server):
        summator_pb2_grpc.add_SummatorServicer_to_server(self, server)

    def register(self):
        self._register_method("sum", None, self.__sum2)

    def __sum2(self, number: summator_pb2.Number1, context: ServicerContext):
        res = summator.sum(number.value1, number.value2)
        return summator_pb2.Number2(value=res)

# Create service
controller = MyGrpcController()
controller.configure(ConfigParams.from_tuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50057
))

controller.set_references(References())

controller.open(None)

Not available

Client

The code for the client is:

// Pre-requisites
let services = require('../summator_grpc_pb');
let messages = require('../summator_pb');

import { ConfigParams, References } from "pip-services4-components-node";
import { GrpcClient } from "pip-services4-grpc-node";

// gRPC client
export class MyGrpcClient extends GrpcClient {
    public constructor() {
        super(services.SummatorClient);
    }

    public async getData(correlationId: string, value1: number, value2: number): Promise<number> {
        let request = new messages.Number1();
        request.setValue1(value1);
        request.setValue2(value2);

        let res = await this.call<any>("sum", correlationId, request);

        return res.getValue();
    }
}
 
let client = new MyGrpcClient();
client.configure(ConfigParams.fromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
));

client.setReferences(new References());

await client.open(null);

// Function call and result
let result = await client.getData(null, 3, 5);  // Returns 8

Not available
Not available
Not available
# Pre-requisites
from pip_services4_grpc.clients import GrpcClient
from pip_services4_components.config import ConfigParams
from pip_services4_components.refer import References

import summator_pb2
import summator_pb2_grpc

# gRPC client
class MyGrpcClient(GrpcClient):
    def __init__(self):
        super().__init__(summator_pb2_grpc.SummatorStub, 'Summator')

    def get_data(self, correlation_id, value1, value2):
        number = summator_pb2.Number1(value1=value1, value2=value2)
        result = self._call("sum", None, number)
        return result.value



# Create client
client = MyGrpcClient()
client.configure(ConfigParams.from_tuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
))

client.open(None)

# Function call and result
result = client.get_data(None, 3, 5)  # Returns 8

print(f'Function result: {result}')
Not available

Proto file

Our proto file looks like this:


syntax = "proto3";

option go_package = "./main";

message Number1 {
    float value1 = 1;
    float value2 = 2;
}

message Number2 {
    float value = 1;
}

service Summator {
    rpc sum(Number1) returns (Number2) {}
}

Proto compiler generated files

The files generated by the protoc compiler are:

summator_pb.js
// source: summator.proto
/**
 * @fileoverview
 * @enhanceable
 * @suppress {missingRequire} reports error on implicit type usages.
 * @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!
/* eslint-disable */
// @ts-nocheck

var jspb = require('google-protobuf');
var goog = jspb;
var global = Function('return this')();

goog.exportSymbol('proto.Number1', null, global);
goog.exportSymbol('proto.Number2', 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.Number1 = function(opt_data) {
  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.Number1, jspb.Message);
if (goog.DEBUG && !COMPILED) {
  /**
   * @public
   * @override
   */
  proto.Number1.displayName = 'proto.Number1';
}
/**
 * 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.Number2 = function(opt_data) {
  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.Number2, jspb.Message);
if (goog.DEBUG && !COMPILED) {
  /**
   * @public
   * @override
   */
  proto.Number2.displayName = 'proto.Number2';
}



if (jspb.Message.GENERATE_TO_OBJECT) {
/**
 * Creates an object representation of this proto.
 * Field names that are reserved in JavaScript and will be renamed to pb_name.
 * Optional fields that are not set will be set to undefined.
 * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
 * For the list of reserved names please see:
 *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
 * @param {boolean=} opt_includeInstance Deprecated. whether to include the
 *     JSPB instance for transitional soy proto support:
 *     http://goto/soy-param-migration
 * @return {!Object}
 */
proto.Number1.prototype.toObject = function(opt_includeInstance) {
  return proto.Number1.toObject(opt_includeInstance, this);
};


/**
 * Static version of the {@see toObject} method.
 * @param {boolean|undefined} includeInstance Deprecated. Whether to include
 *     the JSPB instance for transitional soy proto support:
 *     http://goto/soy-param-migration
 * @param {!proto.Number1} msg The msg instance to transform.
 * @return {!Object}
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.Number1.toObject = function(includeInstance, msg) {
  var f, obj = {
    value1: jspb.Message.getFloatingPointFieldWithDefault(msg, 1, 0.0),
    value2: jspb.Message.getFloatingPointFieldWithDefault(msg, 2, 0.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.Number1}
 */
proto.Number1.deserializeBinary = function(bytes) {
  var reader = new jspb.BinaryReader(bytes);
  var msg = new proto.Number1;
  return proto.Number1.deserializeBinaryFromReader(msg, reader);
};


/**
 * Deserializes binary data (in protobuf wire format) from the
 * given reader into the given message object.
 * @param {!proto.Number1} msg The message object to deserialize into.
 * @param {!jspb.BinaryReader} reader The BinaryReader to use.
 * @return {!proto.Number1}
 */
proto.Number1.deserializeBinaryFromReader = function(msg, reader) {
  while (reader.nextField()) {
    if (reader.isEndGroup()) {
      break;
    }
    var field = reader.getFieldNumber();
    switch (field) {
    case 1:
      var value = /** @type {number} */ (reader.readFloat());
      msg.setValue1(value);
      break;
    case 2:
      var value = /** @type {number} */ (reader.readFloat());
      msg.setValue2(value);
      break;
    default:
      reader.skipField();
      break;
    }
  }
  return msg;
};


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


/**
 * Serializes the given message to binary data (in protobuf wire
 * format), writing to the given BinaryWriter.
 * @param {!proto.Number1} message
 * @param {!jspb.BinaryWriter} writer
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.Number1.serializeBinaryToWriter = function(message, writer) {
  var f = undefined;
  f = message.getValue1();
  if (f !== 0.0) {
    writer.writeFloat(
      1,
      f
    );
  }
  f = message.getValue2();
  if (f !== 0.0) {
    writer.writeFloat(
      2,
      f
    );
  }
};


/**
 * optional float value1 = 1;
 * @return {number}
 */
proto.Number1.prototype.getValue1 = function() {
  return /** @type {number} */ (jspb.Message.getFloatingPointFieldWithDefault(this, 1, 0.0));
};


/**
 * @param {number} value
 * @return {!proto.Number1} returns this
 */
proto.Number1.prototype.setValue1 = function(value) {
  return jspb.Message.setProto3FloatField(this, 1, value);
};


/**
 * optional float value2 = 2;
 * @return {number}
 */
proto.Number1.prototype.getValue2 = function() {
  return /** @type {number} */ (jspb.Message.getFloatingPointFieldWithDefault(this, 2, 0.0));
};


/**
 * @param {number} value
 * @return {!proto.Number1} returns this
 */
proto.Number1.prototype.setValue2 = function(value) {
  return jspb.Message.setProto3FloatField(this, 2, value);
};





if (jspb.Message.GENERATE_TO_OBJECT) {
/**
 * Creates an object representation of this proto.
 * Field names that are reserved in JavaScript and will be renamed to pb_name.
 * Optional fields that are not set will be set to undefined.
 * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
 * For the list of reserved names please see:
 *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
 * @param {boolean=} opt_includeInstance Deprecated. whether to include the
 *     JSPB instance for transitional soy proto support:
 *     http://goto/soy-param-migration
 * @return {!Object}
 */
proto.Number2.prototype.toObject = function(opt_includeInstance) {
  return proto.Number2.toObject(opt_includeInstance, this);
};


/**
 * Static version of the {@see toObject} method.
 * @param {boolean|undefined} includeInstance Deprecated. Whether to include
 *     the JSPB instance for transitional soy proto support:
 *     http://goto/soy-param-migration
 * @param {!proto.Number2} msg The msg instance to transform.
 * @return {!Object}
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.Number2.toObject = function(includeInstance, msg) {
  var f, obj = {
    value: jspb.Message.getFloatingPointFieldWithDefault(msg, 1, 0.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.Number2}
 */
proto.Number2.deserializeBinary = function(bytes) {
  var reader = new jspb.BinaryReader(bytes);
  var msg = new proto.Number2;
  return proto.Number2.deserializeBinaryFromReader(msg, reader);
};


/**
 * Deserializes binary data (in protobuf wire format) from the
 * given reader into the given message object.
 * @param {!proto.Number2} msg The message object to deserialize into.
 * @param {!jspb.BinaryReader} reader The BinaryReader to use.
 * @return {!proto.Number2}
 */
proto.Number2.deserializeBinaryFromReader = function(msg, reader) {
  while (reader.nextField()) {
    if (reader.isEndGroup()) {
      break;
    }
    var field = reader.getFieldNumber();
    switch (field) {
    case 1:
      var value = /** @type {number} */ (reader.readFloat());
      msg.setValue(value);
      break;
    default:
      reader.skipField();
      break;
    }
  }
  return msg;
};


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


/**
 * Serializes the given message to binary data (in protobuf wire
 * format), writing to the given BinaryWriter.
 * @param {!proto.Number2} message
 * @param {!jspb.BinaryWriter} writer
 * @suppress {unusedLocalVariables} f is only used for nested messages
 */
proto.Number2.serializeBinaryToWriter = function(message, writer) {
  var f = undefined;
  f = message.getValue();
  if (f !== 0.0) {
    writer.writeFloat(
      1,
      f
    );
  }
};


/**
 * optional float value = 1;
 * @return {number}
 */
proto.Number2.prototype.getValue = function() {
  return /** @type {number} */ (jspb.Message.getFloatingPointFieldWithDefault(this, 1, 0.0));
};


/**
 * @param {number} value
 * @return {!proto.Number2} returns this
 */
proto.Number2.prototype.setValue = function(value) {
  return jspb.Message.setProto3FloatField(this, 1, value);
};


goog.object.extend(exports, proto);



Summator.cs
Not available
summator.pb.go
Not available
summator.pb.dart
Not available
summator.pbenum.dart
Not available
summator2_pb2.py

```python
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: summator.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)

_sym_db = _symbol_database.Default()




DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0esummator.proto\")\n\x07Number1\x12\x0e\n\x06value1\x18\x01 \x01(\x02\x12\x0e\n\x06value2\x18\x02 \x01(\x02\"\x18\n\x07Number2\x12\r\n\x05value\x18\x01 \x01(\x02\x32\'\n\x08Summator\x12\x1b\n\x03sum\x12\x08.Number1\x1a\x08.Number2\"\x00\x42\x08Z\x06./mainb\x06proto3')



_NUMBER1 = DESCRIPTOR.message_types_by_name['Number1']
_NUMBER2 = DESCRIPTOR.message_types_by_name['Number2']
Number1 = _reflection.GeneratedProtocolMessageType('Number1', (_message.Message,), {
  'DESCRIPTOR' : _NUMBER1,
  '__module__' : 'summator_pb2'
  # @@protoc_insertion_point(class_scope:Number1)
  })
_sym_db.RegisterMessage(Number1)

Number2 = _reflection.GeneratedProtocolMessageType('Number2', (_message.Message,), {
  'DESCRIPTOR' : _NUMBER2,
  '__module__' : 'summator_pb2'
  # @@protoc_insertion_point(class_scope:Number2)
  })
_sym_db.RegisterMessage(Number2)

_SUMMATOR = DESCRIPTOR.services_by_name['Summator']
if _descriptor._USE_C_DESCRIPTORS == False:

  DESCRIPTOR._options = None
  DESCRIPTOR._serialized_options = b'Z\006./main'
  _NUMBER1._serialized_start=18
  _NUMBER1._serialized_end=59
  _NUMBER2._serialized_start=61
  _NUMBER2._serialized_end=85
  _SUMMATOR._serialized_start=87
  _SUMMATOR._serialized_end=126
# @@protoc_insertion_point(module_scope)



Not available
summator_grpc_pb.js
// GENERATED CODE -- DO NOT EDIT!

'use strict';
var grpc = require('grpc');
var summator_pb = require('./summator_pb.js');

function serialize_Number1(arg) {
  if (!(arg instanceof summator_pb.Number1)) {
    throw new Error('Expected argument of type Number1');
  }
  return Buffer.from(arg.serializeBinary());
}

function deserialize_Number1(buffer_arg) {
  return summator_pb.Number1.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_Number2(arg) {
  if (!(arg instanceof summator_pb.Number2)) {
    throw new Error('Expected argument of type Number2');
  }
  return Buffer.from(arg.serializeBinary());
}

function deserialize_Number2(buffer_arg) {
  return summator_pb.Number2.deserializeBinary(new Uint8Array(buffer_arg));
}


var SummatorService = exports.SummatorService = {
  sum: {
    path: '/Summator/sum',
    requestStream: false,
    responseStream: false,
    requestType: summator_pb.Number1,
    responseType: summator_pb.Number2,
    requestSerialize: serialize_Number1,
    requestDeserialize: deserialize_Number1,
    responseSerialize: serialize_Number2,
    responseDeserialize: deserialize_Number2,
  },
};

exports.SummatorClient = grpc.makeGenericClientConstructor(SummatorService);


SummatorGrpc.cs
Not available
summator_grpc.pb.go
Not available
summator.pbgrpc.dart
Not available
summator.pbjson.dart
Not available
summator2_pb2_grpc.py

```python
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc

import summator_pb2 as summator__pb2


class SummatorStub(object):
    """Missing associated documentation comment in .proto file."""

    def __init__(self, channel):
        """Constructor.

        Args:
            channel: A grpc.Channel.
        """
        self.sum = channel.unary_unary(
                '/Summator/sum',
                request_serializer=summator__pb2.Number1.SerializeToString,
                response_deserializer=summator__pb2.Number2.FromString,
                )


class SummatorServicer(object):
    """Missing associated documentation comment in .proto file."""

    def sum(self, request, context):
        """Missing associated documentation comment in .proto file."""
        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
        context.set_details('Method not implemented!')
        raise NotImplementedError('Method not implemented!')


def add_SummatorServicer_to_server(servicer, server):
    rpc_method_handlers = {
            'sum': grpc.unary_unary_rpc_method_handler(
                    servicer.sum,
                    request_deserializer=summator__pb2.Number1.FromString,
                    response_serializer=summator__pb2.Number2.SerializeToString,
            ),
    }
    generic_handler = grpc.method_handlers_generic_handler(
            'Summator', rpc_method_handlers)
    server.add_generic_rpc_handlers((generic_handler,))


 # This class is part of an EXPERIMENTAL API.
class Summator(object):
    """Missing associated documentation comment in .proto file."""

    @staticmethod
    def sum(request,
            target,
            options=(),
            channel_credentials=None,
            call_credentials=None,
            insecure=False,
            compression=None,
            wait_for_ready=None,
            timeout=None,
            metadata=None):
        return grpc.experimental.unary_unary(request, target, '/Summator/sum',
            summator__pb2.Number1.SerializeToString,
            summator__pb2.Number2.FromString,
            options, channel_credentials,
            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)



Not available

Library

In this tutorial’s example, we used the summator file as a library of methods. This file is like this:

export class Calculations {
    public static sum(x: number, y: number): number {
        let z = x + y;
        return z;
    }
}

Not available
Not available
Not available
def sum(x,y):
  z = x + y
  return z
Not available

Wrapping up

In this tutorial, we have learned how to create a gRPC server and client. We also saw how to create a proto file and generate the two gRPC files via the protoc compiler. Finally, we understood how to run the server and the client and obtain a result from a call to the sum() method.