An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

          

# protorails ![test](https://github.com/uiur/protorails/actions/workflows/ruby.yml/badge.svg)

`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).