• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

How to Call gRPC Methods Dynamically in Go

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
gRPC (Google Remote Procedure Call) is a high-performance, open-source framework for making remote procedure calls. Unlike traditional REST APIs that use HTTP/1.1 and JSON, gRPC leverages HTTP/2 and Protocol Buffers for more efficient communication between distributed systems. This modern approach offers significant advantages in terms of performance, type safety, and code generation capabilities.

When working with gRPC, you need to understand the fundamental components and workflow that differentiate it from other API communication methods. The process begins with defining your service interface using Protocol Buffers (protobuf) in a proto file, which serves as a contract between client and server. This definition is then compiled into language-specific code that handles all the underlying communication complexities.

You can make gRPC calls dynamically in two ways: using server reflection or providing uncompiled proto files.

Dynamic Calls Using gRPC Server Reflection


Typically, services are registered with a gRPC server immediately after creation, as shown in the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

example provided by grpc team:


import (
"google.golang.org/grpc"
)

type server struct {
helloworld.UnimplementedGreeterServer
}

func main() {
// ...
s := grpc.NewServer()
helloworld.RegisterGreeterServer(s, &server{})
// ...
}

To enable server reflection, register the reflection service by calling the Register function from the reflection package as follows.


import (
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)

type server struct {
helloworld.UnimplementedGreeterServer
}

func main() {
// ...
s := grpc.NewServer()
helloworld.RegisterGreeterServer(s, &server{})
reflection.Register(s)
// ...
}

After starting the server, you can check the new service by using Kreya's (

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

) server reflection importing. The picture below shows this result with server reflection service:


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Calling gRPC dynamically with reflection involves two steps: first, a request to the ServerReflectionInfo stream retrieves proto files (FileDescriptors). The sequence diagram illustrates this process. Note that for every service call, one call must be made to the reflection service to fetch the proto file.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



The following code implements the process shown in the diagram above. The function grpcurl.DescriptorSourceFromServer retrieves the file descriptor from the reflection service. The call to the target method is done by grpcurl.InvokeRPC function.


package main

import (
"bytes"
"context"
"log"
"strings"

"github.com/fullstorydev/grpcurl"
"github.com/jhump/protoreflect/grpcreflect"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

func main() {
// Inputs
serverAddr := "localhost:50051"
methodFullName := "helloworld.Greeter/SayHello"
jsonRequest := `{ "name": "goodbye, hello goodbye, you say stop and I say go go..." }`

// Output buffer
var output bytes.Buffer

// Create gRPC channel
grpcChannel, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("Failed to dial server: %v", err)
}
defer grpcChannel.Close()

// Create reflection client
reflectionClient := grpcreflect.NewClient(context.Background(), grpcreflect.NewClientV1(grpcChannel))
defer reflectionClient.Reset()

// Use grpcurl to get the method descriptor
descriptorSource := grpcurl.DescriptorSourceFromServer(context.Background(), reflectionClient)

// Prepare formatter for the response
options := grpcurl.FormatOptions{EmitJSONDefaultFields: true}
jsonRequestReader := strings.NewReader(jsonRequest)
rf, formatter, err := grpcurl.RequestParserAndFormatter(grpcurl.Format("json"), descriptorSource, jsonRequestReader, options)
if err != nil {
log.Fatalf("Failed to construct request parser and formatter: %v", err)
}
eventHandler := &grpcurl.DefaultEventHandler{
Out: &output,
Formatter: formatter,
VerbosityLevel: 0,
}

headers := []string{}

err = grpcurl.InvokeRPC(context.Background(), descriptorSource, grpcChannel, methodFullName, headers, eventHandler, rf.Next)
if err != nil {
log.Fatalf("RPC call failed: %v", err)
}
log.Println("Received output:")
log.Print(output.String())
}

The images below show the console outputs from the client and server runs, respectively. You can seem from the log output one call for the stream and other for the target service.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Dynamic Calls Using Proto Files


If you have access to the proto file, you can call the target service directly by changing the function grpcurl.DescriptorSourceFromServer to grpcurl.DescriptorSourceFromProtoFiles . In this way, the steps needed to call the service are simplified as shown in the sequence diagram below.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



The results from the server and client can be seen below, where the stream is not called anymore.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Conclusion


There are two effective approaches for making dynamic gRPC calls. Server reflection offers several advantages: it eliminates the need to maintain proto files on the client side, enables dynamic discovery of services, and simplifies integration testing and debugging tools. With reflection, clients can automatically discover and interact with services without prior knowledge of their interfaces.

However, server reflection does have drawbacks. Each service call requires an additional reflection call, which adds network overhead. While you can mitigate this by caching file descriptors after the first reflection call. Reflection may also expose additional server details that could potentially reduce security.

Alternatively, using proto files directly provides a more efficient approach with fewer network calls, but requires keeping the client's proto files synchronized with the server.

The complete code examples from this article are available at

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу