RubyクラスをJSONでアクセスできるWebサービス化する
Rubyで書いたサービスをCGIにして実行できるようにするのが面倒だったので、クラスをJSONでアクセスできるWebサービスにするクラスを書いてみました。(こういうのをObject Request Brokerというらしい。)
- JSON形式で実行するメソッド名と引数を受け取って、それを元にRubyクラスのメソッドを実行。結果をJSON形式で返します。
- CGIで使えるようにしてみました。getやpostで渡されるパラメータの値をリクエストとします。
Broker(json-broker.rb):
require "json/lexer" require "cgi" module JSONBroker # CGI向けAPI # パラメータ「request」の値をリクエストとして使う。 class Cgi def self.invoke( service ) print "Content-type: application/json\n\n" cgi = CGI.new request = cgi.params["request"].to_s print Broker.new( service ).invoke( request ) end end # JSONリクエストを元にサービスのAPIを実行して結果をJSONで返す。 # # リクエスト: # {"method":<サービスメソッド名>, "params":[<引数1>, <引数2>]} # # レスポンス(正常時): # [{"error":null, "result":<実行結果>}] # # レスポンス(エラー時): # [{"error":<例外の詳細>, "result":null}] # class Broker def initialize ( service ) @service = service end def invoke ( request ) begin json = JSON::Lexer.new(request).nextvalue method = json["method"] args = json["params"] result = @service.send( method, *args ) return '[{"error":null, "result":' << result.to_json << "}]" rescue error = $!.to_s + " : " + $!.backtrace.join("\n") return '[{"error":' << error.to_json << ', "result":null}]' end end end end
CGIは次のような感じで書きます。
require "json-broker" # 公開するサービス class KittenAnalysisService def analysis( kitten ) return kitten["name"] =~ /mii/ ? {:strain=>"Mike"} : {:strain=>"Egyptian"} end end JSONBroker::Cgi.invoke KittenAnalysisService.new
実行サンプル
以下は公開したサービスに対してリクエストを実行した結果。ブラウザで試しました。
正常終了
リクエスト1:
.../service.cgi?request={"method":"analysis","params":[{"name":"kuro"}]}
レスポンス:
[{"error":null, "result":{"strain":"Egyptian"}}]
エラーの場合
リクエスト:
.../service.cgi?request={"method":"analysis","params":[{"name":"shiro"}]}
レスポンス:
[{"error":"test : json-rpc.cgi:9:in `analysis'\n.\/json-broker.rb:41:in `send'\n.\/json-broker.rb:41:in `invoke'\n.\/json-broker.rb:15:in `invoke'\nservice.cgi:14", "result":null}]
補足
ちなみに、Orbjsonというのが既にあります。JSON-RPCを使ってJavaScript/Ruby間でのリモートメソッド呼び出しが簡単に実現できるようです。(未調査)
今回は、これくらいの機能で良かったので自作してみました。