https://github.com/uiur/protorails
A toolkit to build type-safe Rails API with protocol buffers
https://github.com/uiur/protorails
Last synced: 11 months ago
JSON representation
A toolkit to build type-safe Rails API with protocol buffers
- Host: GitHub
- URL: https://github.com/uiur/protorails
- Owner: uiur
- License: mit
- Created: 2021-05-03T05:34:51.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2021-12-17T08:38:13.000Z (over 4 years ago)
- Last Synced: 2025-04-08T22:11:07.129Z (about 1 year ago)
- Language: Ruby
- Homepage:
- Size: 52.7 KB
- Stars: 10
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: MIT-LICENSE
Awesome Lists containing this project
README
# protorails 
`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](https://github.com/twitchtv/twirp).
Write API schema in protobuf, and it can generate API client for [TypeScript, Ruby or Java etc](https://github.com/twitchtv/twirp#implementations-in-other-languages).
The deployment is easy. [Twirp protocol](https://github.com/twitchtv/twirp/blob/master/PROTOCOL.md) 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.
```proto
// 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.
```proto
// app/protos/minishop/order/show_request.proto
syntax = "proto3";
package minishop.order;
message ShowRequest {
string id = 1;
}
```
```proto
// 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:
```sh
$ 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`).
```ruby
# 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.
```ruby
# 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](https://github.com/timostamm/protobuf-ts) with it:
```sh
protoc -I=../app/protos --ts_out=front/src/gen $(find ../app/protos -name '*.proto')
```
It generates api clients and type interface like:
```typescript
const client = new OrderClient(transport)
const { response } = await client.show({ id: orderId })
```
```typescript
/**
* @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:
```sh
$ 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:
```sh
$ 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:
```sh
$ 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:
```ruby
gem 'protorails'
```
And then execute:
```bash
$ bundle
```
Or install it yourself as:
```bash
$ gem install protorails
```
## Contributing
Contribution directions go here.
## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).