ActiveRpc

Rails-native JSONRPC 2.0 Server Library

Usage

ActiveRpc is a simple mechanism to service JSONRPC requests from within a Rails installation without sacrificing your existing Rails workflow. It supports custom before/after/around actions on the RPC controller, and insists upon validation of payloads for inbound method invocations, using standard Rails tools and toolchains.

Installation

Add this line to your application's Gemfile:

gem 'activerpc', '~> 0.1'

And then execute:

$ bundle

Or install it yourself as:

$ gem install activerpc

The final step is to add a mount directive to your routes file, like so:

Rails.application.routes.draw do
  # other routes...
  mount ActiveRpc::Engine => "/rpc"
end

Usage

Operations

The JSONRPC spec supports two kinds of parameters being passed to a method. We feel strongly that only the Hash/Object form should be used rather than the Array/positional form. The reason for this is that it is significantly less brittle as changes happen over time, and much easier to reason about what the job is whilst in flight.

Further than that, we also believe that all invocations should be subject to suitable validation before processing. So...

class MyRpcMethod < ActiveRpc::Operation
  operation_name 'rpc.method.name'
  fields :name, :age

  validates :name, presence: true
  validates :age, presence: true, numericality: true, only_integer: true, greater_than: 18

  def call
    "Hello #{name}, you are #{age} years old."
  end

  before_validation do
    # do something to check on the inputs before validating them
  end
end

ActiveRpc will instantiate your method class, and if it passes validation it will then call #call on it, returning the outcome of that method as the JSONRPC result field.

JSONRPC supports returning application-semantic errors, to trigger one of those you should raise an error in your #call method.

def call
  raise OperationFailure.new(code: my_code, message: 'no thanks') if name == 'Nigel'

  "Hello #{name}, you are #{age} years old."
end

Controller Lifecycle Events

You can provide after or before hooks to tie into the controller lifecycle, whether for authentication, authorization or whatever else.

To provide a hook, you can provide a callable for the method desired to the config object.

ActiveRpc.configure do |config|
  config.before_action = ->{
    authenticate_user!
  }
end

Alternatively, you can use mixins to extend the functionality to get more control.

ActiveRpc::RpcController.send(:include, Module.new do
  extend ActiveSupport::Concern

  included do
    around_action do
      start = Time.now
      yield
      puts "took #{Time.now - start}"
    end
  end
end)

Development Mode

Please note, in development mode you might have issues with the operation classes being autoloaded. The new bootloader in Rails 6 will solve this, but until then you can add something similar to the below to an initialiser.

# Require all operatons in app/operations as dependencies for autoloading
Rails.application.config.to_prepare do
  Dir[Rails.root.join('app', 'operations', '*.rb')].each do |file|
    require_dependency(file)
  end
end

Contributing

Fork the project, make some changes and open a PR! For major changes of direction please talk to us first, we can't guarantee to merge PRs that don't reflect the usage we have of this project.

License

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