おはようございます。
若林(@nqounet)です。

JSON::RPC::Specをアップデートしましたのでお知らせいたします。

JSON::RPC::Specとは

ひとことで言うと、JSON-RPCの仕様のJSON文字列を解釈して結果を返すモジュールです。

詳しくは過去のリリースの時に書いたエントリーをご覧ください。

全くの偶然なのですが、仕事でJSON-RPCの仕様で通信を行う機会がありました。

ただし、通信を暗号化する必要があったり、既存のアプリが持っているデータも使いたいので、アプリの中に組み込めるこのモジュールを使っています。

ただ、実際に使ってみると、要求された仕様で動くように書いていくのは結構大変でした。

特に、任意のエラーを出すことを想定していなかったので、微妙なハックで対応したのですが、とりあえず喉元過ぎれば熱さを忘れるとかいうやつです。

で、それ以外に、どう頑張っても無理そうな事があったので、今回はそれを実現するためにアップデートしました。

アップデート内容の概要

JSON文字列を解釈(parse または parse_without_encode)するとき、その文字列以外にも変数を渡せるようにしました。

その変数は、ディスパッチャを定義(register)で定義する関数で受け取ることができます。

詳細

このモジュールは使うタイミングによってメソッドが分かれています。

ひとつ目はディスパッチャの定義(register)、ふたつ目がJSON文字列を解釈する関数(parse または parse_without_encode)です。

ひとつ目のregisterは、methodによって動作を変えることを想定していて、Router::Simpleの機能を使って各クラス、あるいは関数へ処理を振り分ける定義をします。

method matching via Router::Simple
1
2
3
4
5
$rpc->register('myapp.{action}' => sub {
my ($params, $match) = @_;
my $action = $match->{action};
return MyApp->new->$action($params);
});

モジュールのregisterの説明部分にはこういう書き方をしています。

こうした場合に以下のようなJSON文字列をparseすると、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
```

<p>MyApp.pmに書いてある foo 関数に対して +{key => 'value'} というハッシュを渡す、というふうになります。</p>

<p>registerの第一引数にマッチした内容が $match に渡されるので、methodが「myapp.bar」であれば bar 関数に渡す、という感じです。</p>

<p>そして、ふたつ目のparseは実際のJSON文字列を渡すことで、実際に定義通りに動作する部分です。</p>

<p>この時に渡したい変数があっても、うまく渡す方法が思いつきませんでした。</p>

<p>なので、無理矢理押し込めました。</p>

<h3>サンプル</h3>

<p>少ししっかり目のサンプルを書いてみました。</p>

<p><a href="https://github.com/nqounet/p5-json-rpc-spec/tree/master/examples/extra_args">https://github.com/nqounet/p5-json-rpc-spec/tree/master/examples/extra_args</a></p>

<p>main.plを実行した時、parseの時に、以下のようにして変数を渡すと、</p>

```perl
# https://github.com/nqounet/p5-json-rpc-spec/blob/657ede22dd44be863281e8775602ce7c1e8d20c2/examples/extra_args/main.pl#L25
my $result = $app->jsonrpc->parse($json, $extra_args);

ディスパッチ先(例としては、MyApp::Fooのbar関数)で受け取ることができます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# https://github.com/nqounet/p5-json-rpc-spec/blob/657ede22dd44be863281e8775602ce7c1e8d20c2/examples/extra_args/lib/MyApp/Foo.pm#L10-L22
sub bar {
my $self = shift;

my $params = shift;
my $extra_args = +[@_];

+{
controller => $self->controller,
action => $self->action,
params => $params,
extra_args => $extra_args,
};
}

Mojolicious::Lite のように1枚のファイルに書く場合は不要なのですが、ちゃんとクラスに分けて書こうとすると変数がなかなか渡しづらいので、こういう場面で使えるように考えました。

実際に使おうとしている場面

Mojolicious でシステムを作っているのですが、そのシステムにJSON-RPCの方式で外部からアクセスできるようにしていたのです。

register は アプリ(Mojoliciousを継承しているモジュール) の startup のタイミングで定義しており、実際に処理したいJSON文字列は、コントローラー(Mojolicious::Controllerを継承しているモジュール)に実装しています。

この時、ディスパッチ先でコントローラーが持っているデータを使いたいと思ったら、なかなか難しいことに気づきました。

parseする時にコントローラーを渡すのが最も簡単だったので、今回は素直にこういう実装にしました。

JSON-RPCをアプリに組み込むならJSON::RPC::Spec

JSON::RPC::Specは、バッチについても対応しています。

つまり、完全にJSON-RPCに対応していますので、アプリでJSON-RPCをやるならJSON::RPC::Specが良いと思います。