意外と便利なJSON RPC

 このエントリーはHTML5 Advent Calendar 2012の4日目のエントリーになります。
 JSON RPCとは文字通りJSONでRPCするプロトコルで、現行バージョンは2.0です
 リモート環境にある関数をローカルの関数と同様に呼び出せるRPCは呼びだす機能が多かったり、複雑だったりする時に非常に便利です。またRESTと違い対象がHTTPを受け付けるサーバーである必要がないというメリットがあり、これがwebsocketやメッセージングAPI、webworkerといったHTML5 APIと非常に相性がいいのです。
 またRPCというとXML RPCが有名ですが、JSON RPCはそれにくらべて以下のような特徴を持ちます

  1. プロトコルが軽量・シンプル
  2. 名前つきパラメーター(namedparameter)
  3. バッチリクエスト

 では順番に見ていきます

プロトコルが軽量

 
 RPCに限らずXMLJSONの比較ではなんでもそうなのですが、JSONは非常に軽量でシンプルです。
まずは呼び出しですが

{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}

 これに対して例えば次のようなレスポンスが返ってきます。、

{"jsonrpc": "2.0", "result": 19, "id": 1}


 この例をみれば説明しなくても大体基本的なプロトコルは解ると思います
 具体的には

jsonrpc プロトコルのバージョンを指定します。現在は2.0固定です
method 呼び出すメソッドの名前
params メソッドの引数
id 呼び出し一つ一つに付与されたID。エラーメッセージの返却などに使う
result 結果

 ということになります。
 paramsに設定されるメソッドの引数の順番は呼び出し先の引数の順番にそのまま相当するのですが、JSON RPCにはもうひとつの引数決定方法があります。
 それが名前つき引数です

名前つき引数


リモート側で設定されている以下のような関数をローカル側から呼び出すとします。

function subtract($a,$b){

   return $a - $b ;

}

 
 これは先述のとおり、次のようなリクエストで呼び出すことができます

{"jsonrpc": "2.0", "method": "subtract", "params": [42, 43], "id": 1}

 リモート側では引き算が計算され、返却されます(この場合は-1)。
 この呼び出し方法にはもうひとつ呼び出し方法があり、それが名前つきパラメーターとよばれる方法です。この場合、引数と値のペアをparamsに設定して呼び出します

{"jsonrpc": "2.0", "method": "subtract", "params": {"b":43, "a":42}, "id": 1}

 少し余談になりますが、この呼び出し方法は呼び出す側としては便利なのですが受け取る方の実装は大変です。Python以外の言語ではハッシュを可変引数として投げる機能はないので、実装しているライブラリのソースコードを読むと普段見ることないメタプログラミングに出会えます。
 特に本来は複雑なメタプログラミング機能のないjavascriptにおいては大変興味深く、pmrpc.jsというライブラリは以下のように解決しています。

      var fnDef = fn.toString();#定義文を取得
      var argNames = fnDef.substring(fnDef.indexOf("(")+1, fnDef.indexOf(")"));
      argNames = (argNames === "") ? [] : argNames.split(", ");
   var argIndexes = {};
      for (var i=0; i<argNames.length; i++) {
        argIndexes[argNames[i]] = i;
      }

 evalの逆で関数オブジェクトを文字列変換すると定義文が取得できます。そこから引数の一覧を正規表現で切り出しているわけです。この発想はありませんでした。

バッチリクエスト

 JSON RPCにはもうひとつの特徴としてバッチリクエストがあります。これは一度のリクエストで複数の関数呼び出しを行うもので、ローカル側ではリクエスト回数を減らし、サーバー側ではシステムの部品化がしやすくなります。
 以下の例では四則計算を一度に行っています。

{"jsonrpc": "2.0", "method": "add", "params": {"b":43, "a":42}, "id": 1}
{"jsonrpc": "2.0", "method": "subtract", "params": {"b":43, "a":42}, "id": 1}
{"jsonrpc": "2.0", "method": "multiplication", "params": {"b":43, "a":42}, "id": 1}
{"jsonrpc": "2.0", "method": "divine", "params": {"b":43, "a":42}, "id": 1}

実装

 JSON RPCを実装しているライブラリについては、英語版wikipediaが詳しいです
 見ての通りサーバー、クライアント共に複数の言語で実装されており、よほど特殊な言語で無い限りは問題ありません。

まとめ

 JSON RPCは軽量でかつ強力なプロトコルです。機能も豊富であり、サーバサイドの部品化、再利用化も容易です
 またJSONのテキストがサーバー側に渡ればいいという特徴から通信手法を選ばず、文字列のみでしか通信のできないHTML5 APIとの相性は抜群です。是非試してみてください