· ruby grpc

RubyでgRPC対応する

既存のRailsのRest APIをgRPC対応しました。

gem install

$ gem install grpc
$ gem install grpc-tools

protoファイル作成

api.proto

syntax = "proto3";

package api;

service LGTM {
  rpc Items (ItemsRequest) returns (ItemsResponse) {}
  rpc Upload (UploadRequest) returns (UploadResponse) {}
  rpc Item (ItemRequest) returns (ItemResponse) {}
}

message Item {
    int64 id = 1;
    string url = 2;
}

message ItemsRequest {
  int64 page = 1;
}

message ItemsResponse {
  repeated Item items = 1;
}

message ItemRequest {
  int64 id = 1;
}

message ItemResponse {
  Item item = 1;
}

message UploadRequest {
  string image = 1;
}

message UploadResponse {
  string result = 1;
}

ファイル生成

$ grpc_tools_ruby_protoc -I . --ruby_out=lib --grpc_out=lib ./api.proto

$ tree lib
lib
├── api_pb.rb
├── api_services_pb.rb

Server側

grpc_api_server.rb

#!/usr/bin/env ruby
 
this_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.join(this_dir, 'lib')
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)

require 'grpc'
require 'api_services_pb'
require 'date'
require ::File.expand_path('../config/environment', __FILE__)

class APIServer < Api::LGTM::Service
  def items(req, _unused_call)
    res_items = Array.new()
    items = Item.order("id desc").page(req.page)
    for item in items do
      res_item = Api::Item.new(id: item.id, url: item.url)
      res_items.push(res_item)
    end
    Api::ItemsResponse.new(items: res_items)
  end

  def item(req, _unused_call)
    item = Item.find(req.id)
    res_item = Api::Item.new(id: item.id, url: item.url)
    Api::ItemResponse.new(item: res_item)
  end
end

def main
  s = GRPC::RpcServer.new
  s.add_http2_port('0.0.0.0:5555', :this_port_is_insecure)
  s.handle(APIServer)
  s.run_till_terminated
end

main

Client側

#!/usr/bin/env ruby
 
this_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.join(this_dir, 'lib')
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
 
require 'grpc'
require 'api_services_pb'

def main
  stub = Api::LGTM::Stub.new('localhsot:5555', :this_channel_is_insecure)

  items = stub.items(Api::ItemsRequest.new(page: 1)).items
  p "#{items}"

  item = stub.item(Api::ItemRequest.new(id: 1)).item
  p "#{item.url}"
end

main

テスト

$ ruby grpc_api_server.rb

$ ruby grpc_api_client.rb