uiur / protorails

A toolkit to build type-safe Rails API with protocol buffers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

protorails test

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.

About

A toolkit to build type-safe Rails API with protocol buffers

License:MIT License


Languages

Language:Ruby 85.5%Language:HTML 11.6%Language:JavaScript 1.5%Language:CSS 1.4%