Skip to content

cheddar-me/rails-twirp

Repository files navigation

RailsTwirp

Allows for effortless integration of Twirp endpoints into your Rails application. RailsTwirp permits you to define your Twirp endpoints using the familiar vocabulary of Rails routes, controllers, actions and views.

Using an extra routes file you map your Twirp RPCs to controllers, and define your views using pbbuilder. Even though you are now serving Twirp RPC endpoints instead of HTML or JSON, all the skills and tools you have for working your usual Rails infrastructure apply. TwirpRails provides a customised controller superclass called RailsTwirp::Base which includes all the relevant ActionController components which still make sense when using Protobufs.

Usage

Add the gem to your project (see "Installation" below). Then add a file called config/twirp/routes.rb to your application, and map your RPCs inside of that file. We will map a GreetWorld RPC call as an example:

Rails.application.twirp.routes.draw do
  service HelloService, module: :api do
    rpc "GreetWorld", to: "greetings#greet"
  end
end

The module defines the module which will contain your TwirpRails controller. The HelloService module is your Protobuf mapping generated using Twirp, it inherits from Twirp::Service and could look like this:

class HelloService < Twirp::Service
  package 'api'
  service 'App'
  rpc :GreetWorld, GreetWorldRequest, GreetWorldResponse, :ruby_method => :greet_world
end

The GreetWorldRequest in this case is the autogenerated protobuf request class, the GreetWorldResponse is the response class.

Then you define your controller, which looks like a standard Rails controller - just with a different base class:

class API::GreetingsController  < RailsTwirp::Base
  def greet
    render pb: API::GreetResponse.new
  end
end

Note that the controller is routed using the same naming conventions as Rails. Inside of a TwirpRails controller you can do most of the things you are used to from Rails controllers, such as renders and implicit renders - which have to be pbbuilder views. If our GreetWorldResponse has a greeting field, it can be filled inside the pbbuilder view like so:

pb.greeting "Hello stranger"

Inside the controllers you have access to the call parameters of your RPC call using request:

def greet
  request.name #=> # Returns the value of the "name" field from the request Protobuf
end

Installation

Add this line to your application's Gemfile:

gem 'rails_twirp'

And then execute:

$ bundle

Or install it yourself as:

$ gem install rails_twirp

Installing correct protobuf version for M1 Mac Chips

If you run into an issue with protobuf universal-darwin version, please paste this in your Gemfile as recommended by @bouke :

# HACK(bouk): Overwrite Bundler's platform matcher to ignore universal CPU
# The protobuf and gRPC 'universal' macOS gems break on M1
module Bundler::MatchPlatform
  def match_platform(p)
    return false if ::Gem::Platform === platform && platform.cpu == "universal"
    Bundler::MatchPlatform.platforms_match?(platform, p)
  end
end

Contributing

  • Check out the latest main to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
  • Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
  • Fork the project.
  • Start a feature/bugfix branch.
  • Commit and push until you are happy with your contribution.
  • Make sure to add tests for your change. This is important so we don't break it in a future version unintentionally.
  • Please try not to mess with the Rakefile, version, or history.

License

The gem is available as open source under the terms of the MIT License.