Git Product home page Git Product logo

rails_respond_to_pb's Introduction

rails_respond_to_pb

Gem Version

This gem allows you to route RPC calls via protobuf to an existing rails controller. Currently supporting:

Installation

Add this line to your application's Gemfile:

gem 'rails_respond_to_pb'

And then execute:

bundle install

Or install it yourself as:

gem install rails_respond_to_pb

Usage

This gem loads Rails middleware that routes to services with Controllers as Handlers.

  • assumes a single ThingsService per controller
    • Typical Rails namey-ness conventions are followed here
      • assumes a ThingsService routes to a ThingsController
      • looking into building generating proto files from controllers
  • loads any _twirp.rb files that exist within your app's lib directory
  • allows a controller to respond_to the pb format
    • currently you'd respond with a render plain: ThingResponse.new(id: 1, name: 'Foo').to_proto
      • looking into render pb:

Generate a proto like this for each of your controllers (rpc methods should match your controller methods. message is to your discretion):

syntax = "proto3";

service Things {
  // these rpc methods are important - use what's in the corresponding ThingsController.
  // whatever is sent as an argument will be made available to the controller as `params`
  rpc Create (ThingParams) returns (ThingResponse);
  rpc Show (ThingParams) returns (ThingResponse);
  rpc Index (ThingFilter) returns (ThingList);
  rpc Update (ThingParams) returns (ThingResponse);
  rpc Destroy (ThingParams) returns (ThingResponse);
}

message ThingParams {
  int32 id = 1;
  string name = 2;
}

message ThingFilter {
  string name = 1;
}

message ThingResponse {
  int32 id = 1;
  string name = 2;
}

message ThingList {
  repeated ThingResponse things = 1;
}

Server

This gem will allow your app to respond to Twirp requests. There is little setup required, other than having the prerequisite Service files loaded in your application.

Given a Service file of ThingsService, this gem assumes the presence of a ThingsController with actions corresponding with rpc methods. To allow your controller to respond to the RPC request, simply update the action accordingly:

def index
  # ... business as usual

  respond_to do |format|
    format.pb do
      render plain: ThingList.new(things: Thing.all.map { |r| ThingResponse.new(r.as_json) }).to_proto
    end
    format.json { render: Thing.all.as_json } # or whatever your controller responds to usually
  end
end

The required setup here is:

respond_to do |format|
  format.pb do
    render plain: YourProtoResponse.to_proto

Of note, if you're trying to wire up entirely new methods, you do NOT need this gem at all, and you can simply add this to your routes file:

handler = ThingsHandler.new()
service = ThingsService.new(handler)

mount service, at: service.full_name

Client

Assuming you have the prerequisite Client files loaded in your application, you can connect to a Twirp server as usual:

client = ThingsClient.new('http://localhost:3000')
query = ThingFilter.new name: 'foo'
client.index(query)

Development

I typically add an alias to make working with dockerized apps easier. This assumes docker is running.

alias dr="docker compose run --rm "

After checking out the repo, run dr bundle install to spin up a container, and install dependencies. Then, run dr rspec spec to run the tests. You can also run dr bundle console for an interactive prompt that will allow you to experiment.

To release a new version, update the version number in version.rb, and then run dr bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Building protos

For inspiration on how to build proto files locally (and working with docker-compose), here are some services to use within your application:

services:
  bundle: &bundle # run your typical bundle commands
    env_file: .env
    stdin_open: true
    tty: true
    build: .
    entrypoint: bundle
    command: check
    volumes:
      - .:/usr/src/app:delegated # hot reload your application's code
      - bundle:/usr/local/bundle:delegated # cache bundle installs
      - ~/Projects:/local # used to install gems locally rename ~/Projects to whichever dir your code lives in

  rspec: # run your tests!!
    <<: *bundle
    entrypoint: bundle exec rspec
    command: --version

  protoc: # generate code from proto files
    build: .
    entrypoint: bundle
    command: |
      exec grpc_tools_ruby_protoc
      -I ./lib/protos --ruby_out=./lib/protobuf --twirp_ruby_out=./lib/protobuf
      ./lib/protos/things.proto
    volumes:
      - .:/usr/src/app:delegated
      - bundle:/usr/local/bundle:delegated

The twirp_ruby_out function needs to be made available to your environment. Use a multistage file, like so:

FROM golang:1 AS go
RUN go get github.com/twitchtv/twirp-ruby/protoc-gen-twirp_ruby

# or whatever version of ruby you're using
FROM ruby:3
# Install necessary executable to build protos
COPY --from=go /go/bin /usr/local/bin

Contributing

Bug reports and pull requests are welcome on GitHub. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

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

Code of Conduct

Everyone interacting in the RailsRespondToPb project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

rails_respond_to_pb's People

Contributors

dudo avatar github-actions[bot] avatar shine-garg-chime avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

rails_respond_to_pb's Issues

Support json input

Hey Brett, so I played with twirp a little more and confirmed that the same client and Rails server can be used for pb or json serialization. The default is pb but adding content_type: "application/json" forces json ser. You can uncomment that line in hello_client,rb and play with it. This comes in very handy when hitting the server from the commandline for some quick debugging or, say, for k8 health checks.

However, in the middleware case (#34), it seems to be either pb or json. Not sure how much we should bend on our back to support both, but it's worth understanding why the difference exists. Maybe we don't need to support json because the middleware will likely be used for migrating existing services to twirp and they already have a ping controller. Or maybe it's still a handy debugging tool worth looking into?

@shine-garg-chime has some concerns with json input.

support non-200 responses

๐Ÿ‘‹

I happened to stumble on this gem, seems to be well-thought-out and well-written! ๐Ÿ‘

Was trying to incorporate it into a work project that uses doorkeeper, but noticed that using before_action :doorkeeper_authorize! in my controller (analogous to authenticate_user! in devise) didn't work as expected; despite the rails log showing:

Filter chain halted as :doorkeeper_authorize! rendered or redirected
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms | Allocations: 232)

...the client ultimately still received a 200 response.

I can try and dig in when I can but any help would be appreciated! (I'm not super familiar with the way ActionDispatch works)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.