JSON-RPC over HTTPなサーバを作る
JSON-RPC 2.0 over HTTPなRPCサーバをrubyで実装してみる。
RESTfullに定義できないアクションを持つAPIサーバを作る必要があってRPCサーバか、じゃJSON-RPCで作ってみるかと。どんなものかと週末手を動かしてみた。
JSON-RPC 2.0 の仕様はこちらで薄い仕様なのでさくっと読むべし。なお、JSON-RPC 2.0 にはトランスポート層の指定がないので、TCP、UDP、websocket、HTTPなど用途に応じて決めれる。今回はHTTP上で動作させることにした。
例として足し算するsum(10,20) => 30
こういうRPCを作ってみる。
$ curl -v -s -S \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "method": "sum", "params": [10, 20], "id": 1}' \
http://localhost:8080
> POST / HTTP/1.1
> Host: localhost:8080
> Accept: application/json
> Content-Type: application/json
> Content-Length: 64
>
< HTTP/1.1 200 OK
< Date: Sun, 20 Mar 2016 13:39:21 GMT
< Connection: close
< Content-Length: 36
< X-Runtime: 0.004520
<
{
"jsonrpc": "2.0",
"result": 30,
"id": 1
}
方針
サーバ実装の方針を立てる
- HTTP部分
- Rack
- WAF不要。つまりRails/Sinatra使わない
- Webサーバ(Webric, unicorn, pumaなど好きなもの)
- JSON-RPCサーバ
- リクエスト、呼び出し関数へのディスパッチ処理、レスポンス)実装が必要
- 自作する? しない?
HTTP層はRackに乗っかるとして、WAF(RailsやSinatraなど)が不要なのは、RPCサーバゆえエントリーポイント(パス)は1個、つまりルーティング不要、またレスポンスはjsonで返すだけでviewレンダリングがいらないので、WAFいらないやとなった。シンプルだ。
図示するとサーバのスタックとしては以下になる。
+----------------------------+ ^
| RPC Handlers | |
+----------------------------+ | rack app
| JSON-RPC implementation | |
+----------------------------+ v
| Rack |
+----------------------------+
| Web Server(Unicorn or etc)|
+----------------------------+
^ |
req | v resp HTTP
Client
作る
JSON-RPCの仕様薄いから自作するかとか一瞬おもったけど、一旦落ち着いてRubyの実装を探したところjimsonというgemが自分が実装したいイメージと同じだったので、実装せず使わせてもらう。
jimsonには
- JSON-RPC clientクラス
- JSON-RPC serverクラス (中身はrack app)
- JSON-RPC request, responseクラス
- 各種エラークラス
- handler用のベース
が同封されているので、RPC handler、serverクラスはjimsonがベースにすることになる。
handlerクラス
RPCの実装部分。簡単ですね。
# my_handler.rb
require 'jimson'
class MyHandler
extend Jimson::Handler
def sum(a,b)
a + b
end
end
rackup
# config.ru
require 'jimson'
require_relative 'my_handler'
# middlewares that you want to use
use Rack::Reloader,0
use Rack::Runtime
run Jimson::Server.new(MyHandler.new)
こう書いて、$ bundle exec rackup
とか $ bundle exec unicorn
とかすればよろしい。
ネスト
ちなみにjimsonはfoo.hello
, bar.baz.say
といったnapespaceつきのJSON-RPC methodも定義可能。
# config.ru
require 'jimson'
# require handlers
router = Jimson::Router.new
router.draw do
namespace 'foo', Foo # Foo is expected to implement hello()
namespace 'bar' do
namespace 'baz', Baz # Baz is expected to implement say()
end
end
run Jimson::Server.new(router)
2016/4/13 update: なお、.
区切でしかnamespace表現出来ない仕様だったのでAdd Router :ns_sep option for custom namespace #31でpull reqして任意のセパレータ使えるようお願い中。
ToDo
- リクエストパラメタのバリデーション。外部から渡された値をハンドラにバリデーション無しで渡すのは危険なので、json schemaとか?
- APIのversioning
Author And Source
この問題について(JSON-RPC over HTTPなサーバを作る), 我々は、より多くの情報をここで見つけました https://qiita.com/nikushi/items/bdef1e360729042673ad著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .