Introduced gRPC client to rails

Background

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.

Implementation procedure

1. Introducing gem

Gemfile



gem "google-protobuf" 
gem "grpc-tools"
gem "gruf"
docker-compose run --rm web bundle install
2. Register the repository where the proto file is managed as a subdirectory of the application with the submodule, and fetch the proto file from the original repository.
$ git submodule add [web URL or ssh key] proto
$ git submodule init
$ cd proto
$ git submodule update
3. Compile the proto file into a ruby file
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内の対象ファイル]
4. Read setting of ruby file (* _pb.rb) after compilation

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
5. Implementation of the part where the client calls the server

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.

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

Impressions of introducing it

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

Introduced gRPC client to rails
Rails6 jQuery introduced
Introduced Vue.js to an existing Rails app
How to use credentials.yml.enc introduced in Rails 5.2
Introduced Vuetify to an existing Rails app
How to write Rails
Introducing Bootstrap to Rails 5
Introducing Bootstrap to Rails !!
Introduce Vue.js to Rails
How to uninstall Rails
[rails] How to post images
[Rails] How to use enum
[Rails] How to use enum
How to read rails routes
How to use rails join
[Rails] Add column to devise
Introduced Dozer to Play Framework
[Rails] How to use validation
[Rails] How to disable turbolinks
Pass parameters to Rails link_to
[Rails] How to use authenticate_user!
[Rails] How to implement scraping
How to write Rails routing
[Rails] How to install simple_calendar
[Rails] How to use Scope
[Rails] How to use devise (Note)
[Rails] Two ways to write form_with
[Rails] How to use flash messages
[rails] How to display db information
Preparing to create a Rails application
[Rails] Learn yield to understand content_for
[Ruby on Rails] Introduced paging function
Introducing full calendar to Rails application
[Rails] How to prevent screen transition
[Rails] Various ways to delete data
How to use Ruby on Rails
[Rails] Easy way to check columns
How to deploy Bootstrap on Rails
Until you introduce fonts to Rails
[Rails] How to speed up docker-compose
[Rails] How to add new pages
Implement a gRPC client in Ruby
[Rails] How to write exception handling?
[Rails] How to install ImageMagick (RMajick)
[Rails] How to install Font Awesome
[Rails] How to use Active Storage
[Rails] Add strong parameters to devise
How to introduce jQuery in Rails 6
[Rails] How to implement star rating
Connect to Rails server with iPhone
Introducing React to Rails with react-rails
[Introduction to Rails] How to use render
How to install Swiper in Rails
Introduced # 9 serializer to build bulletin board API with authentication authorization in Rails 6