Twirp services are defined with a DSL in Ruby. But that DSL can be autogenerated from the Proto file. This is good because whenever the service definition is modified in the Proto file, you can just re-generate the service definition in Ruby with a single command. However, there are a few steps to properly setup code-generation.
Install tools for code-generation
protoc
Protocol Buffers v3 provides the
protoc
command that is used to auto-generate code.
- MacOS:
brew install protobuf
- Ubuntu/Debian:
sudo apt-get install -y protobuf
- Or download pre-compiled binaries: https://github.com/google/protobuf/releases
Protoc is able to read .proto files and generate the message parsers in multiple languages, including Ruby (using the --ruby_out
option). But it can not generate Twirp services and clients.
Twirp-Ruby Plugin
Twirp-Ruby includes a Golang plugin to allow protoc generate .twirp.rb
files.
Install Golang: https://golang.org/doc/install (in Mac you can also do brew install go
).
Then use go get
to install the twirp_ruby protoc plugin:
go get github.com/arthurnn/twirp-ruby/protoc-gen-twirp_ruby
Code Generation
Once protoc and the twirp_ruby plugins are installed, you can generate messages and service definitions with the command:
protoc --proto_path=. --ruby_out=. --twirp_ruby_out=. ./path/to/service.proto
Example
Given a .proto file hello_world/service.proto
syntax = "proto3";
package example;
service HelloWorld {
rpc Hello(HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
Run protoc pointing to the .proto file:
protoc --proto_path=. --ruby_out=. --twirp_ruby_out=. ./hello_world/service.proto
That will generate two files in the same folder.
Message Definitions:
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: hello_world/service.proto
require 'google/protobuf'
Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "example.HelloRequest" do
optional :name, :string, 1
end
add_message "example.HelloResponse" do
optional :message, :string, 1
end
end
module Example
HelloRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("example.HelloRequest").msgclass
HelloResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("example.HelloResponse").msgclass
end
Twirp Service:
# Code generated by protoc-gen-twirp_ruby, DO NOT EDIT.
require 'twirp'
module Example
class HelloWorldService < Twirp::Service
package "example"
service "HelloWorld"
rpc :Hello, HelloRequest, HelloResponse, :ruby_method => :hello
end
class HelloWorldClient < Twirp::Client
client_for HelloWorldService
end
end