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-services3-grpc-nodex --save
dotnet add package PipServices3.Grpc
go get -u github.com/pip-services3-go/pip-services3-grpc-go@latest
dart pub add pip_services3_grpc
pip install pip-services3-grpc
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

For C# add next configs to project file csproj

<ItemGroup>
  <PackageReference Include="Grpc.Tools" Version="2.23.0" PrivateAssets="All" />
  <Protobuf Include="summator.proto" Link="summator.proto" OutputDir="."/>
</ItemGroup>

See Add a .proto file to a C# app

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative bin/protos/summator.proto 
protoc -I bin/protos/ bin/protos/summator.proto --dart_out=grpc:bin/generated
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. summator.proto
Not available

And the generated files are:

  1. summator_pb: contains message classes
    a. Number1: describes the types of the input paramters.
    b. Number2: describes the result’s type.
  2. summator_grpc_pb: contains server and client classes:
    a. SummatorServicer
    b. SummatorStub
  1. Summator.cs contains all the protocol buffer code to populate, serialize, and retrieve our request and response message types
  2. SummatorGrpc.cs provides generated client and server classes, including:
    • the abstract class Summator.SummatorBase that is inherited when defining Summator service implementations.
    • the class Summator.SummatorClient used to access remote Summator instances.
  1. summator.pb.go, which contains all the protocol buffer code to populate, serialize, and retrieve request and response message types.
  2. summator_grpc.pb.go, which contains the following:
    • An interface type (or stub) for clients with the methods defined in the Summator service.
    • An interface type for servers to implement with the methods defined in the Summator service.

This contains:

  • All the protocol buffer code to populate, serialize, and retrieve our request and response message types
  • An interface type (or stub) for clients with the methods defined in the RouteGuide service.
  • An interface type for servers to implement with the methods defined in the RouteGuide service.

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;
    }
}
namespace Calculations
{
    public class Summator
    {
        public static float Sum(float x, float y)
        {
            var z = x + y;
            return z;
        }
    }
}
package calculations

func Summator(x float32, y float32) float32 {
	z := x + y
	return z
}
double summator(double x, double y) {
  var z = x + y;
  return z;
}

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 { GrpcService } from "pip-services3-grpc-nodex";
using PipServices3.Grpc.Services;
import (
    grpcserv "github.com/pip-services3-go/pip-services3-grpc-go/services"
)
import 'package:pip_services3_grpc/pip_services3_grpc.dart';
from pip_services3_grpc.services import GrpcService
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');

For C#, these files are by default in the same namespace unless otherwise specified.

See gRPC services with C#

import (
    "mymodule/protos"
)
import 'generated/summator.pbgrpc.dart' as command;
import summator2_pb2
import summator2_pb2_grpc
Not available
Library of functions

And the library with the function available from the server.

import { Calculations } from "./calculations";
using Calculations;
import (
    "mymodule/calculations"
)
import 'summator.dart';
import summator
Not available
ServerCallContext

In C#, we also need to consider the ServerCallContext from grpc.

using Grpc.Core;
Context

In Golang, we also need to consider the context package from grpc.

import (
    "context"
)
ServiceCall

In Dart, we also need to consider the ServerCallContext from grpc.

import 'package:grpc/grpc.dart';
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 MyGrpcService extends GrpcService {

    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
        );
    }
}
public class MyGrpcService : GrpcService
{
    public MyGrpcService() : base("my_data_v1") { }

    private async Task<Number2> Sum(Number1 number, ServerCallContext context)
    {
        var res = Calculations.Summator.Sum(number.Value1, number.Value2);
        return new Number2() { Value= res };
    }

    protected override void OnRegister()
    {
        RegisterMethod<Number1, Number2>("sum", Sum);
    }
}
type MyGrpcService struct {
	grpcservices.GrpcService
	protos.SummatorServer
}

func NewMyGrpcService() *MyGrpcService {
	c := &MyGrpcService{}
	c.GrpcService = *grpcservices.InheritGrpcService(c, "Summator")
	return c
}

func (c *MyGrpcService) Sum(ctx context.Context, req *protos.Number1) (result *protos.Number2, err error) {

	res := calculations.Summator(req.GetValue1(), req.GetValue2())
	result = &protos.Number2{Value: res}
	return result, nil
}

func (c *MyGrpcService) Register() {
	protos.RegisterSummatorServer(c.Endpoint.GetServer(), c)
}
class MyGrpcService extends command.SummatorServiceBase with GrpcService {
  MyGrpcService() {
    serviceName = 'Summator.service';
  }

  @override
  Future<command.Number2> sum(ServiceCall call, command.Number1 request) async {
    var res = summator(request.value1, request.value2);
    return command.Number2(value: res);
  }

  @override
  void register() {
    registerService(this);
  }
}
class MyGrpcService(GrpcService, 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

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

import { ConfigParams, References } from "pip-services3-commons-nodex";

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

service.setReferences(new References());

using PipServices3.Commons.Config;

var service = new MyGrpcService();
service.Configure(ConfigParams.FromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
));

service.SetReferences(new References());

import (
    cconf "github.com/pip-services3-go/pip-services3-commons-go/config"
    cref "github.com/pip-services3-go/pip-services3-commons-go/refer"
)

service := NewMyGrpcService()
service.Configure(cconf.NewConfigParamsFromTuples(
	"connection.protocol", "http",
	"connection.host", "localhost",
	"connection.port", 50055,
))

service.SetReferences(cref.NewEmptyReferences())

import 'package:pip_services3_commons/pip_services3_commons.dart';

var service = MyGrpcService();
service.configure(ConfigParams.fromTuples([
  'connection.protocol', 'http',
  'connection.host', 'localhost',
  'connection.port', 50055
]));

service.setReferences(References());

from pip_services3_commons.config import ConfigParams, References

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

service.set_references(References());

Not available
Running the service

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

await service.open(null);
await service.OpenAsync("123");
err := service.Open("123")
await service.open("123");
service.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-services3-grpc-nodex";
using PipServices3.Grpc.Clients;
import (
    grpcclients "github.com/pip-services3-go/pip-services3-grpc-go/clients"
)
import 'package:pip_services3_grpc/pip_services3_grpc.dart';
from pip_services3_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');

For C# add next configs to project file csproj

<ItemGroup>
  <PackageReference Include="Grpc.Tools" Version="2.23.0" PrivateAssets="All" />
  <Protobuf Include="summator.proto" Link="summator.proto" OutputDir="."/>
</ItemGroup>

See gRPC services with C#

import (
    "mymodule/protos"
)
import 'generated/summator.pbgrpc.dart' as command;

import summator2_pb2
import summator2_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();
    }
}
class MyGrpcClient(GrpcClient):
     def __init__(self):
        super().__init__(summator2_pb2_grpc.SummatorStub, 'Summator')
        
     def get_data(self, correlation_id, value1, value2):
        number = summator2_pb2.Number1(value1=value1, value2=value2)
        result = self._call("sum", None, number)
        return result.value
type MyGrpcClient struct {
	*grpcclients.GrpcClient
}

func NewMyGrpcClient() *MyGrpcClient {
	dgc := MyGrpcClient{}
	dgc.GrpcClient = grpcclients.NewGrpcClient("Summator")
	return &dgc
}

func (c *MyGrpcClient) GetData(correlationId string, value1 float32, value2 float32) (result float32, err error) {

	req := &protos.Number1{Value1: value1, Value2: value2}
	reply := new(protos.Number2)
	err = c.Call("sum", correlationId, req, reply)
	if err != nil {
		return 0, err
	}
	result = reply.GetValue()

	return result, nil
}
class MyGrpcClient extends GrpcClient {
  MyGrpcClient() : super('Summator');

  Future<double> getData(
      String? correlationId, double value1, double value2) async {
    var request = command.Number1(value1: value1, value2: value2);
    var response = await call<command.Number1, command.Number2>(
        'sum', correlationId, request);

    return response.writeToJsonMap().values.toList()[0];
  }
}
class MyGrpcClient(GrpcClient):
     def __init__(self):
        super().__init__(summator2_pb2_grpc.SummatorStub, 'Summator')
        
     def get_data(self, correlation_id, value1, value2):
        number = summator2_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-services3-commons-nodex";

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

client.setReferences(new References());
using PipServices3.Commons.Config;

var client = new MyGrpcClient();
client.Configure(ConfigParams.FromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
));

client.SetReferences(new References());
import (
    cconf "github.com/pip-services3-go/pip-services3-commons-go/config"
    cref "github.com/pip-services3-go/pip-services3-commons-go/refer"
)

client := NewMyGrpcClient()
client.Configure(cconf.NewConfigParamsFromTuples(
	"connection.protocol", "http",
	"connection.host", "localhost",
	"connection.port", 50055,
))
client.SetReferences(cref.NewEmptyReferences())
import 'package:pip_services3_commons/pip_services3_commons.dart';

var client = MyGrpcClient();
client.configure(ConfigParams.fromTuples([
  "connection.protocol", "http",
  'connection.host', 'localhost', 
  'connection.port', 50055
]));

client.setReferences(References());
from pip_services3_commons.config import ConfigParams, 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);
await client.OpenAsync(null);
err := client.Open("123")
await client.open(null);
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
var result = await client.GetData(null, 3, 5);  // Returns 8
result, err := client.GetData("123", 3, 5) // Returns 8
var result = await client.getData(null, 3, 5); // Returns 8
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-services3-commons-nodex";
import { GrpcService } from "pip-services3-grpc-nodex";
import { Calculations } from "./calculations";

// gRPC server
export class MyGrpcService extends GrpcService {

    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 service = new MyGrpcService();
service.configure(ConfigParams.fromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
));

service.setReferences(new References());

await service.open(null);
// Pre-requisites
using Grpc.Core;
using System;
using System.Threading.Tasks;

using PipServices3.Commons.Config;
using PipServices3.Grpc.Services;

using Calculations;

// gRPC server
public class MyGrpcService : GrpcService
{
    public MyGrpcService() : base("my_data_v1") { }

    private async Task<Number2> Sum(Number1 number, ServerCallContext context)
    {
        var res = Calculations.Summator.Sum(number.Value1, number.Value2);
        return new Number2() { Value = res };
    }

    protected override void OnRegister()
    {
        RegisterMethod<Number1, Number2>("sum", Sum);
    }
}
    
var service = new MyGrpcService();
service.Configure(ConfigParams.FromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
));

service.SetReferences(new References());

await service.OpenAsync(null);
// Pre-requisites
import (
	"context"
	"fmt"
	"mymodule/calculations"
	"mymodule/protos"

	cconf "github.com/pip-services3-go/pip-services3-commons-go/config"
	cref "github.com/pip-services3-go/pip-services3-commons-go/refer"
	grpcclients "github.com/pip-services3-go/pip-services3-grpc-go/clients"
)

// gRPC server
type MyGrpcService struct {
	grpcservices.GrpcService
	protos.SummatorServer
}

func NewMyGrpcService() *MyGrpcService {
	c := &MyGrpcService{}
	c.GrpcService = *grpcservices.InheritGrpcService(c, "Summator")
	return c
}

func (c *MyGrpcService) Sum(ctx context.Context, req *protos.Number1) (result *protos.Number2, err error) {

	res := calculations.Summator(req.GetValue1(), req.GetValue2())
	result = &protos.Number2{Value: res}
	return result, nil
}

func (c *MyGrpcService) Register() {
	protos.RegisterSummatorServer(c.Endpoint.GetServer(), c)
}
    
service := NewMyGrpcService()
service.Configure(cconf.NewConfigParamsFromTuples(
	"connection.protocol", "http",
	"connection.host", "localhost",
	"connection.port", 50055,
))

service.SetReferences(cref.NewEmptyReferences())

err := service.Open("123")
// Pre-requisites
import 'package:grpc/grpc.dart';
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_grpc/pip_services3_grpc.dart';

import 'generated/summator.pbgrpc.dart' as command;
import 'summator.dart';

// gRPC server
class MyGrpcService extends command.SummatorServiceBase with GrpcService {
  MyGrpcService() {
    serviceName = 'Summator';
  }

  @override
  Future<command.Number2> sum(ServiceCall call, command.Number1 request) async {
    var res = summator(request.value1, request.value2);
    return command.Number2(value: res);
  }

  @override
  void register() {
    registerService(this);
  }
}
    
var client = MyGrpcClient();
client.configure(ConfigParams.fromTuples([
  "connection.protocol", "http",
    'connection.host', 'localhost', 
    'connection.port', 50055
]));

client.setReferences(References());

await service.open(null);
# Pre-requisites
import time
from grpc import ServicerContext
from pip_services3_grpc.services import GrpcService
from pip_services3_commons.config import ConfigParams
from pip_services3_commons.refer import References

import summator

import summator_pb2
import summator_pb2_grpc

# gRPC service


class MyGrpcService(GrpcService, 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
service = MyGrpcService()
service.configure(ConfigParams.from_tuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
))

service.set_references(References())

service.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, Descriptor, References } from "pip-services3-commons-nodex";
import { GrpcClient } from "pip-services3-grpc-nodex";
import { Calculations } from "./calculations";

// 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
// Pre-requisites
using System;
using System.Threading.Tasks;

using PipServices3.Commons.Config;
using PipServices3.Grpc.Clients;

// gRPC client
public class MyGrpcClient: GrpcClient
{
    public MyGrpcClient(): base("Summator") { }

    public async Task<float> GetData(string correlationId, float value1, float value2)
    {
        var number = new Number1() { Value1=value1, Value2 = value2};
        var result = await CallAsync<Number1, Number2>("sum", number);
        return result.Value;
    }
}

    
var client = new MyGrpcClient();
client.Configure(ConfigParams.FromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 50055
));

client.SetReferences(new References());

await client.OpenAsync(null);

// Function call and result
var result = await client.GetData(null, 3, 5);  // Returns 8
// Pre-requisites
import (
	"context"
	"fmt"
	"mymodule/calculations"
	"mymodule/protos"

	cconf "github.com/pip-services3-go/pip-services3-commons-go/config"
	cref "github.com/pip-services3-go/pip-services3-commons-go/refer"
	grpcclients "github.com/pip-services3-go/pip-services3-grpc-go/clients"
	grpcservices "github.com/pip-services3-go/pip-services3-grpc-go/services"
)

// gRPC client
type MyGrpcClient struct {
	*grpcclients.GrpcClient
}

func NewMyGrpcClient() *MyGrpcClient {
	dgc := MyGrpcClient{}
	dgc.GrpcClient = grpcclients.NewGrpcClient("Summator")
	return &dgc
}

func (c *MyGrpcClient) GetData(correlationId string, value1 float32, value2 float32) (result float32, err error) {

	req := &protos.Number1{Value1: value1, Value2: value2}
	reply := new(protos.Number2)
	err = c.Call("sum", correlationId, req, reply)
	if err != nil {
		return 0, err
	}
	result = reply.GetValue()

	return result, nil
}
 
client := NewMyGrpcClient()
client.Configure(cconf.NewConfigParamsFromTuples(
	"connection.protocol", "http",
	"connection.host", "localhost",
	"connection.port", 50055,
))

client.SetReferences(cref.NewEmptyReferences())

err := client.Open("123")

// Function call and result
result, err := client.GetData("123", 3, 5) // Returns 8
// Pre-requisites
import 'package:grpc/grpc.dart';
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_grpc/pip_services3_grpc.dart';

import 'generated/summator.pbgrpc.dart' as command;
import 'summator.dart';

// gRPC server
class MyGrpcClient extends GrpcClient {
  MyGrpcClient() : super('Summator');

  Future<double> getData(
      String? correlationId, double value1, double value2) async {
    var request = command.Number1(value1: value1, value2: value2);
    var response = await call<command.Number1, command.Number2>(
        'sum', correlationId, request);

    return response.writeToJsonMap().values.toList()[0];
  }
}
    
var client = MyGrpcClient();
client.configure(ConfigParams.fromTuples([
  "connection.protocol", "http",
  'connection.host', 'localhost', 
  'connection.port', 50055
]));

client.setReferences(References());

await service.open(null);
# Pre-requisites
from pip_services3_grpc.clients import GrpcClient
from pip_services3_commons.config import ConfigParams
from pip_services3_commons.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
// <auto-generated>
//     Generated by the protocol buffer compiler.  DO NOT EDIT!
//     source: summator.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code

using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
/// <summary>Holder for reflection information generated from summator.proto</summary>
public static partial class SummatorReflection {

  #region Descriptor
  /// <summary>File descriptor for summator.proto</summary>
  public static pbr::FileDescriptor Descriptor {
    get { return descriptor; }
  }
  private static pbr::FileDescriptor descriptor;

  static SummatorReflection() {
    byte[] descriptorData = global::System.Convert.FromBase64String(
        string.Concat(
          "Cg5zdW1tYXRvci5wcm90byIpCgdOdW1iZXIxEg4KBnZhbHVlMRgBIAEoAhIO",
          "CgZ2YWx1ZTIYAiABKAIiGAoHTnVtYmVyMhINCgV2YWx1ZRgBIAEoAjInCghT",
          "dW1tYXRvchIbCgNTdW0SCC5OdW1iZXIxGgguTnVtYmVyMiIAYgZwcm90bzM="));
    descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
        new pbr::FileDescriptor[] { },
        new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
          new pbr::GeneratedClrTypeInfo(typeof(global::Number1), global::Number1.Parser, new[]{ "Value1", "Value2" }, null, null, null),
          new pbr::GeneratedClrTypeInfo(typeof(global::Number2), global::Number2.Parser, new[]{ "Value" }, null, null, null)
        }));
  }
  #endregion

}
#region Messages
public sealed partial class Number1 : pb::IMessage<Number1> {
  private static readonly pb::MessageParser<Number1> _parser = new pb::MessageParser<Number1>(() => new Number1());
  private pb::UnknownFieldSet _unknownFields;
  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public static pb::MessageParser<Number1> Parser { get { return _parser; } }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public static pbr::MessageDescriptor Descriptor {
    get { return global::SummatorReflection.Descriptor.MessageTypes[0]; }
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  pbr::MessageDescriptor pb::IMessage.Descriptor {
    get { return Descriptor; }
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public Number1() {
    OnConstruction();
  }

  partial void OnConstruction();

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public Number1(Number1 other) : this() {
    value1_ = other.value1_;
    value2_ = other.value2_;
    _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public Number1 Clone() {
    return new Number1(this);
  }

  /// <summary>Field number for the "value1" field.</summary>
  public const int Value1FieldNumber = 1;
  private float value1_;
  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public float Value1 {
    get { return value1_; }
    set {
      value1_ = value;
    }
  }

  /// <summary>Field number for the "value2" field.</summary>
  public const int Value2FieldNumber = 2;
  private float value2_;
  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public float Value2 {
    get { return value2_; }
    set {
      value2_ = value;
    }
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public override bool Equals(object other) {
    return Equals(other as Number1);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public bool Equals(Number1 other) {
    if (ReferenceEquals(other, null)) {
      return false;
    }
    if (ReferenceEquals(other, this)) {
      return true;
    }
    if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Value1, other.Value1)) return false;
    if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Value2, other.Value2)) return false;
    return Equals(_unknownFields, other._unknownFields);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public override int GetHashCode() {
    int hash = 1;
    if (Value1 != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Value1);
    if (Value2 != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Value2);
    if (_unknownFields != null) {
      hash ^= _unknownFields.GetHashCode();
    }
    return hash;
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public override string ToString() {
    return pb::JsonFormatter.ToDiagnosticString(this);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public void WriteTo(pb::CodedOutputStream output) {
    if (Value1 != 0F) {
      output.WriteRawTag(13);
      output.WriteFloat(Value1);
    }
    if (Value2 != 0F) {
      output.WriteRawTag(21);
      output.WriteFloat(Value2);
    }
    if (_unknownFields != null) {
      _unknownFields.WriteTo(output);
    }
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public int CalculateSize() {
    int size = 0;
    if (Value1 != 0F) {
      size += 1 + 4;
    }
    if (Value2 != 0F) {
      size += 1 + 4;
    }
    if (_unknownFields != null) {
      size += _unknownFields.CalculateSize();
    }
    return size;
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public void MergeFrom(Number1 other) {
    if (other == null) {
      return;
    }
    if (other.Value1 != 0F) {
      Value1 = other.Value1;
    }
    if (other.Value2 != 0F) {
      Value2 = other.Value2;
    }
    _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public void MergeFrom(pb::CodedInputStream input) {
    uint tag;
    while ((tag = input.ReadTag()) != 0) {
      switch(tag) {
        default:
          _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
          break;
        case 13: {
          Value1 = input.ReadFloat();
          break;
        }
        case 21: {
          Value2 = input.ReadFloat();
          break;
        }
      }
    }
  }

}

public sealed partial class Number2 : pb::IMessage<Number2> {
  private static readonly pb::MessageParser<Number2> _parser = new pb::MessageParser<Number2>(() => new Number2());
  private pb::UnknownFieldSet _unknownFields;
  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public static pb::MessageParser<Number2> Parser { get { return _parser; } }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public static pbr::MessageDescriptor Descriptor {
    get { return global::SummatorReflection.Descriptor.MessageTypes[1]; }
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  pbr::MessageDescriptor pb::IMessage.Descriptor {
    get { return Descriptor; }
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public Number2() {
    OnConstruction();
  }

  partial void OnConstruction();

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public Number2(Number2 other) : this() {
    value_ = other.value_;
    _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public Number2 Clone() {
    return new Number2(this);
  }

  /// <summary>Field number for the "value" field.</summary>
  public const int ValueFieldNumber = 1;
  private float value_;
  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public float Value {
    get { return value_; }
    set {
      value_ = value;
    }
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public override bool Equals(object other) {
    return Equals(other as Number2);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public bool Equals(Number2 other) {
    if (ReferenceEquals(other, null)) {
      return false;
    }
    if (ReferenceEquals(other, this)) {
      return true;
    }
    if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Value, other.Value)) return false;
    return Equals(_unknownFields, other._unknownFields);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public override int GetHashCode() {
    int hash = 1;
    if (Value != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Value);
    if (_unknownFields != null) {
      hash ^= _unknownFields.GetHashCode();
    }
    return hash;
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public override string ToString() {
    return pb::JsonFormatter.ToDiagnosticString(this);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public void WriteTo(pb::CodedOutputStream output) {
    if (Value != 0F) {
      output.WriteRawTag(13);
      output.WriteFloat(Value);
    }
    if (_unknownFields != null) {
      _unknownFields.WriteTo(output);
    }
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public int CalculateSize() {
    int size = 0;
    if (Value != 0F) {
      size += 1 + 4;
    }
    if (_unknownFields != null) {
      size += _unknownFields.CalculateSize();
    }
    return size;
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public void MergeFrom(Number2 other) {
    if (other == null) {
      return;
    }
    if (other.Value != 0F) {
      Value = other.Value;
    }
    _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
  }

  [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
  public void MergeFrom(pb::CodedInputStream input) {
    uint tag;
    while ((tag = input.ReadTag()) != 0) {
      switch(tag) {
        default:
          _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
          break;
        case 13: {
          Value = input.ReadFloat();
          break;
        }
      }
    }
  }

}

#endregion


#endregion Designer generated code

summator.pb.go
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.

package protos

import (
	context "context"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
)

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7

// SummatorClient is the client API for Summator service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SummatorClient interface {
	Sum(ctx context.Context, in *Number1, opts ...grpc.CallOption) (*Number2, error)
}

type summatorClient struct {
	cc grpc.ClientConnInterface
}

func NewSummatorClient(cc grpc.ClientConnInterface) SummatorClient {
	return &summatorClient{cc}
}

func (c *summatorClient) Sum(ctx context.Context, in *Number1, opts ...grpc.CallOption) (*Number2, error) {
	out := new(Number2)
	err := c.cc.Invoke(ctx, "/Summator/sum", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// SummatorServer is the server API for Summator service.
// All implementations must embed UnimplementedSummatorServer
// for forward compatibility
type SummatorServer interface {
	Sum(context.Context, *Number1) (*Number2, error)
	mustEmbedUnimplementedSummatorServer()
}

// UnimplementedSummatorServer must be embedded to have forward compatible implementations.
type UnimplementedSummatorServer struct {
}

func (UnimplementedSummatorServer) Sum(context.Context, *Number1) (*Number2, error) {
	return nil, status.Errorf(codes.Unimplemented, "method Sum not implemented")
}
func (UnimplementedSummatorServer) mustEmbedUnimplementedSummatorServer() {}

// UnsafeSummatorServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to SummatorServer will
// result in compilation errors.
type UnsafeSummatorServer interface {
	mustEmbedUnimplementedSummatorServer()
}

func RegisterSummatorServer(s grpc.ServiceRegistrar, srv SummatorServer) {
	s.RegisterService(&Summator_ServiceDesc, srv)
}

func _Summator_Sum_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(Number1)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(SummatorServer).Sum(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/Summator/sum",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(SummatorServer).Sum(ctx, req.(*Number1))
	}
	return interceptor(ctx, in, info, handler)
}

// Summator_ServiceDesc is the grpc.ServiceDesc for Summator service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Summator_ServiceDesc = grpc.ServiceDesc{
	ServiceName: "Summator",
	HandlerType: (*SummatorServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "sum",
			Handler:    _Summator_Sum_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "bin/protos/summator.proto",
}

summator.pb.dart
///
//  Generated code. Do not modify.
//  source: summator.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields

import 'dart:core' as $core;

import 'package:protobuf/protobuf.dart' as $pb;

class Number1 extends $pb.GeneratedMessage {
  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Number1', createEmptyInstance: create)
    ..a<$core.double>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value1', $pb.PbFieldType.OF)
    ..a<$core.double>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value2', $pb.PbFieldType.OF)
    ..hasRequiredFields = false
  ;

  Number1._() : super();
  factory Number1({
    $core.double? value1,
    $core.double? value2,
  }) {
    final _result = create();
    if (value1 != null) {
      _result.value1 = value1;
    }
    if (value2 != null) {
      _result.value2 = value2;
    }
    return _result;
  }
  factory Number1.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
  factory Number1.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
  @$core.Deprecated(
  'Using this can add significant overhead to your binary. '
  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
  'Will be removed in next major version')
  Number1 clone() => Number1()..mergeFromMessage(this);
  @$core.Deprecated(
  'Using this can add significant overhead to your binary. '
  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
  'Will be removed in next major version')
  Number1 copyWith(void Function(Number1) updates) => super.copyWith((message) => updates(message as Number1)) as Number1; // ignore: deprecated_member_use
  $pb.BuilderInfo get info_ => _i;
  @$core.pragma('dart2js:noInline')
  static Number1 create() => Number1._();
  Number1 createEmptyInstance() => create();
  static $pb.PbList<Number1> createRepeated() => $pb.PbList<Number1>();
  @$core.pragma('dart2js:noInline')
  static Number1 getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Number1>(create);
  static Number1? _defaultInstance;

  @$pb.TagNumber(1)
  $core.double get value1 => $_getN(0);
  @$pb.TagNumber(1)
  set value1($core.double v) { $_setFloat(0, v); }
  @$pb.TagNumber(1)
  $core.bool hasValue1() => $_has(0);
  @$pb.TagNumber(1)
  void clearValue1() => clearField(1);

  @$pb.TagNumber(2)
  $core.double get value2 => $_getN(1);
  @$pb.TagNumber(2)
  set value2($core.double v) { $_setFloat(1, v); }
  @$pb.TagNumber(2)
  $core.bool hasValue2() => $_has(1);
  @$pb.TagNumber(2)
  void clearValue2() => clearField(2);
}

class Number2 extends $pb.GeneratedMessage {
  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Number2', createEmptyInstance: create)
    ..a<$core.double>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value', $pb.PbFieldType.OF)
    ..hasRequiredFields = false
  ;

  Number2._() : super();
  factory Number2({
    $core.double? value,
  }) {
    final _result = create();
    if (value != null) {
      _result.value = value;
    }
    return _result;
  }
  factory Number2.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
  factory Number2.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
  @$core.Deprecated(
  'Using this can add significant overhead to your binary. '
  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
  'Will be removed in next major version')
  Number2 clone() => Number2()..mergeFromMessage(this);
  @$core.Deprecated(
  'Using this can add significant overhead to your binary. '
  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
  'Will be removed in next major version')
  Number2 copyWith(void Function(Number2) updates) => super.copyWith((message) => updates(message as Number2)) as Number2; // ignore: deprecated_member_use
  $pb.BuilderInfo get info_ => _i;
  @$core.pragma('dart2js:noInline')
  static Number2 create() => Number2._();
  Number2 createEmptyInstance() => create();
  static $pb.PbList<Number2> createRepeated() => $pb.PbList<Number2>();
  @$core.pragma('dart2js:noInline')
  static Number2 getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Number2>(create);
  static Number2? _defaultInstance;

  @$pb.TagNumber(1)
  $core.double get value => $_getN(0);
  @$pb.TagNumber(1)
  set value($core.double v) { $_setFloat(0, v); }
  @$pb.TagNumber(1)
  $core.bool hasValue() => $_has(0);
  @$pb.TagNumber(1)
  void clearValue() => clearField(1);
}

summator.pbenum.dart
///
//  Generated code. Do not modify.
//  source: summator.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
summator2_pb2.py
# -*- 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
// <auto-generated>
//     Generated by the protocol buffer compiler.  DO NOT EDIT!
//     source: summator.proto
// </auto-generated>
#pragma warning disable 0414, 1591
#region Designer generated code

using grpc = global::Grpc.Core;

public static partial class Summator
{
  static readonly string __ServiceName = "Summator";

  static readonly grpc::Marshaller<global::Number1> __Marshaller_Number1 = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Number1.Parser.ParseFrom);
  static readonly grpc::Marshaller<global::Number2> __Marshaller_Number2 = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Number2.Parser.ParseFrom);

  static readonly grpc::Method<global::Number1, global::Number2> __Method_Sum = new grpc::Method<global::Number1, global::Number2>(
      grpc::MethodType.Unary,
      __ServiceName,
      "sum",
      __Marshaller_Number1,
      __Marshaller_Number2);

  /// <summary>Service descriptor</summary>
  public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
  {
    get { return global::SummatorReflection.Descriptor.Services[0]; }
  }

  /// <summary>Base class for server-side implementations of Summator</summary>
  [grpc::BindServiceMethod(typeof(Summator), "BindService")]
  public abstract partial class SummatorBase
  {
    public virtual global::System.Threading.Tasks.Task<global::Number2> Sum(global::Number1 request, grpc::ServerCallContext context)
    {
      throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
    }

  }

  /// <summary>Client for Summator</summary>
  public partial class SummatorClient : grpc::ClientBase<SummatorClient>
  {
    /// <summary>Creates a new client for Summator</summary>
    /// <param name="channel">The channel to use to make remote calls.</param>
    public SummatorClient(grpc::ChannelBase channel) : base(channel)
    {
    }
    /// <summary>Creates a new client for Summator that uses a custom <c>CallInvoker</c>.</summary>
    /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
    public SummatorClient(grpc::CallInvoker callInvoker) : base(callInvoker)
    {
    }
    /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
    protected SummatorClient() : base()
    {
    }
    /// <summary>Protected constructor to allow creation of configured clients.</summary>
    /// <param name="configuration">The client configuration.</param>
    protected SummatorClient(ClientBaseConfiguration configuration) : base(configuration)
    {
    }

    public virtual global::Number2 Sum(global::Number1 request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
    {
      return Sum(request, new grpc::CallOptions(headers, deadline, cancellationToken));
    }
    public virtual global::Number2 Sum(global::Number1 request, grpc::CallOptions options)
    {
      return CallInvoker.BlockingUnaryCall(__Method_Sum, null, options, request);
    }
    public virtual grpc::AsyncUnaryCall<global::Number2> SumAsync(global::Number1 request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
    {
      return SumAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
    }
    public virtual grpc::AsyncUnaryCall<global::Number2> SumAsync(global::Number1 request, grpc::CallOptions options)
    {
      return CallInvoker.AsyncUnaryCall(__Method_Sum, null, options, request);
    }
    /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
    protected override SummatorClient NewInstance(ClientBaseConfiguration configuration)
    {
      return new SummatorClient(configuration);
    }
  }

  /// <summary>Creates service definition that can be registered with a server</summary>
  /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
  public static grpc::ServerServiceDefinition BindService(SummatorBase serviceImpl)
  {
    return grpc::ServerServiceDefinition.CreateBuilder()
        .AddMethod(__Method_Sum, serviceImpl.Sum).Build();
  }

  /// <summary>Register service method with a service binder with or without implementation. Useful when customizing the  service binding logic.
  /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
  /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
  /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
  public static void BindService(grpc::ServiceBinderBase serviceBinder, SummatorBase serviceImpl)
  {
    serviceBinder.AddMethod(__Method_Sum, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::Number1, global::Number2>(serviceImpl.Sum));
  }

}
#endregion

summator_grpc.pb.go
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.27.1
// 	protoc        v3.17.3
// source: bin/protos/summator.proto

package protos

import (
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
	reflect "reflect"
	sync "sync"
)

const (
	// Verify that this generated code is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
	// Verify that runtime/protoimpl is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

type Number1 struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Value1 float32 `protobuf:"fixed32,1,opt,name=value1,proto3" json:"value1,omitempty"`
	Value2 float32 `protobuf:"fixed32,2,opt,name=value2,proto3" json:"value2,omitempty"`
}

func (x *Number1) Reset() {
	*x = Number1{}
	if protoimpl.UnsafeEnabled {
		mi := &file_bin_protos_summator_proto_msgTypes[0]
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
		ms.StoreMessageInfo(mi)
	}
}

func (x *Number1) String() string {
	return protoimpl.X.MessageStringOf(x)
}

func (*Number1) ProtoMessage() {}

func (x *Number1) ProtoReflect() protoreflect.Message {
	mi := &file_bin_protos_summator_proto_msgTypes[0]
	if protoimpl.UnsafeEnabled && x != nil {
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
		if ms.LoadMessageInfo() == nil {
			ms.StoreMessageInfo(mi)
		}
		return ms
	}
	return mi.MessageOf(x)
}

// Deprecated: Use Number1.ProtoReflect.Descriptor instead.
func (*Number1) Descriptor() ([]byte, []int) {
	return file_bin_protos_summator_proto_rawDescGZIP(), []int{0}
}

func (x *Number1) GetValue1() float32 {
	if x != nil {
		return x.Value1
	}
	return 0
}

func (x *Number1) GetValue2() float32 {
	if x != nil {
		return x.Value2
	}
	return 0
}

type Number2 struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Value float32 `protobuf:"fixed32,1,opt,name=value,proto3" json:"value,omitempty"`
}

func (x *Number2) Reset() {
	*x = Number2{}
	if protoimpl.UnsafeEnabled {
		mi := &file_bin_protos_summator_proto_msgTypes[1]
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
		ms.StoreMessageInfo(mi)
	}
}

func (x *Number2) String() string {
	return protoimpl.X.MessageStringOf(x)
}

func (*Number2) ProtoMessage() {}

func (x *Number2) ProtoReflect() protoreflect.Message {
	mi := &file_bin_protos_summator_proto_msgTypes[1]
	if protoimpl.UnsafeEnabled && x != nil {
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
		if ms.LoadMessageInfo() == nil {
			ms.StoreMessageInfo(mi)
		}
		return ms
	}
	return mi.MessageOf(x)
}

// Deprecated: Use Number2.ProtoReflect.Descriptor instead.
func (*Number2) Descriptor() ([]byte, []int) {
	return file_bin_protos_summator_proto_rawDescGZIP(), []int{1}
}

func (x *Number2) GetValue() float32 {
	if x != nil {
		return x.Value
	}
	return 0
}

var File_bin_protos_summator_proto protoreflect.FileDescriptor

var file_bin_protos_summator_proto_rawDesc = []byte{
	0x0a, 0x19, 0x62, 0x69, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x73, 0x75, 0x6d,
	0x6d, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x39, 0x0a, 0x07, 0x4e,
	0x75, 0x6d, 0x62, 0x65, 0x72, 0x31, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31,
	0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x12, 0x16,
	0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x06,
	0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x22, 0x1f, 0x0a, 0x07, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72,
	0x32, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02,
	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x27, 0x0a, 0x08, 0x53, 0x75, 0x6d, 0x6d, 0x61,
	0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x12, 0x08, 0x2e, 0x4e, 0x75, 0x6d,
	0x62, 0x65, 0x72, 0x31, 0x1a, 0x08, 0x2e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, 0x22, 0x00,
	0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72,
	0x6f, 0x74, 0x6f, 0x33,
}

var (
	file_bin_protos_summator_proto_rawDescOnce sync.Once
	file_bin_protos_summator_proto_rawDescData = file_bin_protos_summator_proto_rawDesc
)

func file_bin_protos_summator_proto_rawDescGZIP() []byte {
	file_bin_protos_summator_proto_rawDescOnce.Do(func() {
		file_bin_protos_summator_proto_rawDescData = protoimpl.X.CompressGZIP(file_bin_protos_summator_proto_rawDescData)
	})
	return file_bin_protos_summator_proto_rawDescData
}

var file_bin_protos_summator_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_bin_protos_summator_proto_goTypes = []interface{}{
	(*Number1)(nil), // 0: Number1
	(*Number2)(nil), // 1: Number2
}
var file_bin_protos_summator_proto_depIdxs = []int32{
	0, // 0: Summator.sum:input_type -> Number1
	1, // 1: Summator.sum:output_type -> Number2
	1, // [1:2] is the sub-list for method output_type
	0, // [0:1] is the sub-list for method input_type
	0, // [0:0] is the sub-list for extension type_name
	0, // [0:0] is the sub-list for extension extendee
	0, // [0:0] is the sub-list for field type_name
}

func init() { file_bin_protos_summator_proto_init() }
func file_bin_protos_summator_proto_init() {
	if File_bin_protos_summator_proto != nil {
		return
	}
	if !protoimpl.UnsafeEnabled {
		file_bin_protos_summator_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
			switch v := v.(*Number1); i {
			case 0:
				return &v.state
			case 1:
				return &v.sizeCache
			case 2:
				return &v.unknownFields
			default:
				return nil
			}
		}
		file_bin_protos_summator_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
			switch v := v.(*Number2); i {
			case 0:
				return &v.state
			case 1:
				return &v.sizeCache
			case 2:
				return &v.unknownFields
			default:
				return nil
			}
		}
	}
	type x struct{}
	out := protoimpl.TypeBuilder{
		File: protoimpl.DescBuilder{
			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
			RawDescriptor: file_bin_protos_summator_proto_rawDesc,
			NumEnums:      0,
			NumMessages:   2,
			NumExtensions: 0,
			NumServices:   1,
		},
		GoTypes:           file_bin_protos_summator_proto_goTypes,
		DependencyIndexes: file_bin_protos_summator_proto_depIdxs,
		MessageInfos:      file_bin_protos_summator_proto_msgTypes,
	}.Build()
	File_bin_protos_summator_proto = out.File
	file_bin_protos_summator_proto_rawDesc = nil
	file_bin_protos_summator_proto_goTypes = nil
	file_bin_protos_summator_proto_depIdxs = nil
}

summator.pbgrpc.dart
///
//  Generated code. Do not modify.
//  source: summator.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields

import 'dart:async' as $async;

import 'dart:core' as $core;

import 'package:grpc/service_api.dart' as $grpc;
import 'summator.pb.dart' as $0;
export 'summator.pb.dart';

class SummatorClient extends $grpc.Client {
  static final _$sum = $grpc.ClientMethod<$0.Number1, $0.Number2>(
      '/Summator/sum',
      ($0.Number1 value) => value.writeToBuffer(),
      ($core.List<$core.int> value) => $0.Number2.fromBuffer(value));

  SummatorClient($grpc.ClientChannel channel,
      {$grpc.CallOptions? options,
      $core.Iterable<$grpc.ClientInterceptor>? interceptors})
      : super(channel, options: options, interceptors: interceptors);

  $grpc.ResponseFuture<$0.Number2> sum($0.Number1 request,
      {$grpc.CallOptions? options}) {
    return $createUnaryCall(_$sum, request, options: options);
  }
}

abstract class SummatorServiceBase extends $grpc.Service {
  $core.String get $name => 'Summator';

  SummatorServiceBase() {
    $addMethod($grpc.ServiceMethod<$0.Number1, $0.Number2>(
        'sum',
        sum_Pre,
        false,
        false,
        ($core.List<$core.int> value) => $0.Number1.fromBuffer(value),
        ($0.Number2 value) => value.writeToBuffer()));
  }

  $async.Future<$0.Number2> sum_Pre(
      $grpc.ServiceCall call, $async.Future<$0.Number1> request) async {
    return sum(call, await request);
  }

  $async.Future<$0.Number2> sum($grpc.ServiceCall call, $0.Number1 request);
}

summator.pbjson.dart
///
//  Generated code. Do not modify.
//  source: summator.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields

import 'dart:async' as $async;

import 'dart:core' as $core;

import 'package:grpc/service_api.dart' as $grpc;
import 'summator.pb.dart' as $0;
export 'summator.pb.dart';

class SummatorClient extends $grpc.Client {
  static final _$sum = $grpc.ClientMethod<$0.Number1, $0.Number2>(
      '/Summator/sum',
      ($0.Number1 value) => value.writeToBuffer(),
      ($core.List<$core.int> value) => $0.Number2.fromBuffer(value));

  SummatorClient($grpc.ClientChannel channel,
      {$grpc.CallOptions? options,
      $core.Iterable<$grpc.ClientInterceptor>? interceptors})
      : super(channel, options: options, interceptors: interceptors);

  $grpc.ResponseFuture<$0.Number2> sum($0.Number1 request,
      {$grpc.CallOptions? options}) {
    return $createUnaryCall(_$sum, request, options: options);
  }
}

abstract class SummatorServiceBase extends $grpc.Service {
  $core.String get $name => 'Summator';

  SummatorServiceBase() {
    $addMethod($grpc.ServiceMethod<$0.Number1, $0.Number2>(
        'sum',
        sum_Pre,
        false,
        false,
        ($core.List<$core.int> value) => $0.Number1.fromBuffer(value),
        ($0.Number2 value) => value.writeToBuffer()));
  }

  $async.Future<$0.Number2> sum_Pre(
      $grpc.ServiceCall call, $async.Future<$0.Number1> request) async {
    return sum(call, await request);
  }

  $async.Future<$0.Number2> sum($grpc.ServiceCall call, $0.Number1 request);
}

summator2_pb2_grpc.py
# 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;
    }
}
namespace Calculations
{
    public class Summator
    {
        public static float Sum(float x, float y)
        {
            var z = x + y;
            return z;
        }
    }
}
package calculations

func Summator(x float32, y float32) float32 {
	z := x + y
	return z
}

double summator(double x, double y) {
  var z = x + y;
  return z;
}

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.