Since it is necessary to get information from other services in the implementation of the product (Rails) in charge of PM in the company, and the API interface was defined by gRPC instead of OpenAPI, implement the gRPC client. Did. Since I was a little touching around gRPC in rails in my previous job, I thought that it would increase the development man-hours of the team relatively if I did it, so I decided to do it myself. The output about it.
Gemfile
gem "google-protobuf"
gem "grpc-tools"
gem "gruf"
docker-compose run --rm web bundle install
$ git submodule add [web URL or ssh key] proto
$ git submodule init
$ cd proto
$ git submodule update
docker-compose run --rm web grpc_tools_ruby_protoc -I [Proto directory to compile] --ruby_out=[Directory where files are saved after compilation] --grpc_out=[Directory where files are saved after compilation] [Proto directory to compile内の対象ファイル]
After compiling, the file name and class name do not mesh with each other, and it does not follow Rails loading rules and is not automatically loaded, so you need to specify it.
config/initializers/gruf.rb
require "gruf"
Gruf.configure do
Dir.glob(Rails.root.join("[Directory where files are saved after compilation]/*_pb.rb")).each do |file|
require file
end
end
In the compiled file, it is automatically specified as shown below, and it is necessary to add it to ʻauto_load_path. From e.g. [gruf-demo](https://github.com/bigcommerce/gruf-demo/blob/master/app/rpc/app/proto/Products_services_pb.rb)
require 'Products_pb'`
config/application.rb
class Application < Rails::Application
config.paths.add [Compiled ruby file directory], eager_load: true
end
Up to this point, the client implementation now that all compiled ruby files can be used.
I was worried about whether to use a module, but in the existing implementation, the client-related processing was integrated in the service layer, so I decided to follow it this time as well.
metadata
depends on the implementation on the server side.
gruf wiki at client initialization (Gruf :: Client.new
) I was a little worried because this area is different from this implementation, such as entering ʻusername with the key of the ʻoptions
argument of.app/services/grpc_client_service.rb
class GrpcClientService
def initialize
@metadata = {
login: ENV["GRPC_CLIENT"],
password: ENV["GRPC_PASSWORD"]
}
end
def run(service_klass, method, request)
client = Gruf::Client.new(
service: service_klass,
options: {
hostname: ENV["GRPC_HOST"],
channel_credentials: :this_channel_is_insecure
}
)
client.call(method, request.to_h, @metadata)
end
end
I used gruf in my previous job, so I thought I could afford it, but I thought it would be quite different from just using it. I regret that I should have read the code around the settings.
Also, this time the gRPC server was written in go, and when the call from the client did not go well, I had a hard time reading the code and eventually gave up, so I wanted to study go as well.
Also, I got a little stuck because I misunderstood that I put metadata
at the time of client initialization (Gruf :: Client.new
) (actually I put it in the argument at the time of call), so I wrote it in the library Wiki After all, I realized once again that it is a rudimentary thing that I have to read the code firmly.
Recommended Posts