protorails
is a toolkit to build type-safe API on Rails with Protocol Buffers (protobuf).
It's built on twitch's battle-tested Twirp protocol.
Write API schema in protobuf, and it can generate API client for TypeScript, Ruby or Java etc.
The deployment is easy. Twirp protocol is over HTTP 1.1. The server is just an ordinary Rails application. You can integrate it easily onto an existing Rails application.
Features
- Generators to generate protobuf definitions from models
- Auto-reloading protobuf definitions in development
- Zeitwerk support (Rails 6)
Overview
schema
First, you need to define API interfaces. (They can be defined with generators)
In twirp, schema of API endpoints is defined by service and rpc.
// app/protos/minishop/order/order_service.proto
syntax = "proto3";
import "minishop/order/show_request.proto";
import "minishop/order/order_resource.proto";
package minishop.order;
service Order {
rpc Show(ShowRequest) returns (OrderResource);
}
And schema of request and response is protobuf message.
// app/protos/minishop/order/show_request.proto
syntax = "proto3";
package minishop.order;
message ShowRequest {
string id = 1;
}
// app/protos/minishop/order/order_resource.proto
syntax = "proto3";
import "google/protobuf/timestamp.proto";
package minishop.order;
message OrderResource {
enum Status {
CART = 0;
ORDERED = 1;
}
string id = 1;
Status status = 2;
google.protobuf.Timestamp created_at = 5;
google.protobuf.Timestamp updated_at = 6;
}
implementation
And compile the protobuf files to Ruby:
$ bin/rails proto:compile
# This runs protobuf compilers (protoc)
Implement API actions just like usual Rails controllers:
Return value of an action must match the schema of API response (minishop.order.OrderResource
).
# app/controllers/orders_controller.rb
class OrdersController < Protorails::BaseController
# ::Minishop::Order::OrderService is generated by protoc in: app/gens/minishop/order/order_service_twirp.rb
service ::Minishop::Order::OrderService
def show
order = Order.find(rpc_request.id)
order.as_json(only: [:id, :status, :created_at, :updated_at])
end
end
The routing is defined automatically.
# config/routes.rb
Rails.application.routes.draw do
define_protorails_routes
# This automatically defines: POST /twirp/minishop.order.Order/Show => orders#show
end
api client
You can generate API clients from these definitions with protoc plugins.
If you want one in TypeScript, combine protoc and its ts plugin with it:
protoc -I=../app/protos --ts_out=front/src/gen $(find ../app/protos -name '*.proto')
It generates api clients and type interface like:
const client = new OrderClient(transport)
const { response } = await client.show({ id: orderId })
/**
* @generated from protobuf message minishop.order.OrderResource
*/
export interface OrderResource {
/**
* @generated from protobuf field: string id = 1;
*/
id: string
/**
* @generated from protobuf field: minishop.order.OrderResource.Status status = 2;
*/
status: OrderResource_Status
/**
* @generated from protobuf field: int32 amount = 3;
*/
amount: number
}
Usage
By default, this gem assumes a project has:
- protobuf files under
app/protos
- compiled Ruby protobuf files in
app/gens
Use generator to bootstrap service:
$ bin/rails g proto:service order show
create app/protos/minishop/order/order_service.proto
create app/protos/minishop/order/show_request.proto
create app/protos/minishop/order/show_response.proto
You can specify package name:
$ bin/rails g proto:service order show --package minishop.v1.order
create app/protos/minishop/v1/order/order_service.proto
create app/protos/minishop/v1/order/show_request.proto
create app/protos/minishop/v1/order/show_response.proto
Generate an equivalent protobuf definition from a model:
$ bin/rails g proto:resource order
Status
alpha: prototype for proof of concept
There's a sample application: https://github.com/uiur/minishop
Installation
Add this line to your application's Gemfile:
gem 'protorails'
And then execute:
$ bundle
Or install it yourself as:
$ gem install protorails
Contributing
Contribution directions go here.
License
The gem is available as open source under the terms of the MIT License.