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.