Go で始める JSON-RPC 入門

Gopher artwork is taken from gophericons. Created by Olga Shalakhina, based on original work by Renée French. Licensed under Creative Commons 3.0 Attributions.

この記事は、 Go Advent Calendar 2016 の 15 日目の記事です。

みなさんは、JSON-RPC を使ったことがありますか?
この記事では、 Go で JSON-RPC を使用する方法をレクチャーしたいと思います。(※ この記事は、 golang.tokyo #2 での LT 内容をベースに加筆修正を加えたものになります。)

JSON-RPC とは

概要

JSON-RPC は、 JSON を媒体とした Remote Procedure Call です。

そのため、 Content-Type: application/json で Request と Response をやり取りします。また、 RPC なので Endpoint も任意で決めた Path のみとなります。

JSON-RPC の利点のひとつに、新しく覚える要素がほとんど無いという点があります。最新の仕様である、 JSON-RPC 2.0 も、コンパクトな内容でシンプルです。

簡単な例

Echo という method を定義し、Request で name を受け取ったら、 Response の message という Property に Hello, {{name}} という文字列を生成して返却するとします。

そうすると、Request は、

{
"jsonrpc": "2.0",
"method": "Echo",
"params": {
"name": "John Doe"
},
"id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}

となり、 Response は、

{
"jsonrpc": "2.0",
"result": {
"message": "Hello, John Doe"
},
"id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}

となります。

標準 Package での JSON-RPC

Go には、 net/rpc/jsonrpc というPackage があり、標準で JSON-RPC をサポートしています。

実装例

上記のように実装することが、出来ます。

また、上記の実装では省いていますが、 Debug Handler も付属しており、登録済みの Method 一覧と Call 数を確認することが出来ます。

The debug html page by Debug Handler

標準 Package での所感

  • 実装を通して、 RPC をレクチャーしてくれる Go らしさを感じる。
  • JSON-RPC 2.0 の仕様は満たしていない。
  • HTTP で受け取るには、 net.Conn を取り出さないといけない。
  • Package 内を覗くと reflect を多用している印象がある。

Third Party Package での JSON-RPC

Gorilla Toolkit が、JSON-RPC 2.0 の仕様を実装してくれています。

実装例

上記のように実装することが、出来ます。

定義してある、 Interface が変更されていて、第一引数で *http.Request を受け取ることが出来るようになっています。また、 net.Conn を取り出すことも無く、 Codec を登録し Handler を Endpoint に設定するだけになっています。

Gorilla Toolkit での所感

  • 標準 Package を踏襲しつつ、扱いやすくなっている。
  • Go 1.6 以下だと、 context.Context を持ち運べない。
  • Custom Error を返却したい場合 data を書き込めないなど、すこし手の届かないところがある。

オススメの Package

結構、いろいろな Package を見て回ったのですが…、ありませんでした。

ないので、 github.com/osamingo/jsonrpc を作りました。

README.md

実装例

上記のように実装することが、出来ます。

各 Method に対応する jsonrpc.Func を満たす関数を定義して行きます。 jsonrpc.RegisterMethod に Method 名と関数を登録し、 Endpoint を設定します。

Gorilla Toolkit との差異

  • reflect を使わず、 Method Repository という形で、 map を利用して Method 名と関数ポインタを紐付けています。
  • Go の Version に関わらず、 context.Context を持ち運ぶようにしています。 Google App Engine の Standerd Environment に対応しています。
  • Endpoint が任意で決めた Path のみとなり Swagger や、 API Blueprint 等のツールに対応出来ません。
    なので、 Debug Handler を用意し、登録してある Method 一覧と各 Method に紐付く Params, Result の JSON Schema を自動生成するようにしました。具体的には、下記のような Response を返却します。
Access to the debug endpoint

まとめ

全体を通して、まとめるとこのような感じになります。

  • JSON-RPC は既存知識の組み合わせなので、シンプル且つ簡単である。
  • Go は、標準 Package で、 JSON-RPC をサポートしている。
  • Gorilla Toolkit は、標準 Package を踏襲しつつ、JSON-RPC 2.0 の仕様を実装してくれている。
  • osamingo/jsonrpc は、JSON-RPC 2.0 の仕様を満たし、よりシンプルに、より Debug しやすくなっている。また、 context.Context をサポートしているので、 Google App Engine でも使える。

Go で始める JSON-RPC 入門は、いかがだったでしょうか。
仕様自体もとてもシンプルで、 RPC を学ぶ上では分かりやすい例だったと思います。この記事が、お役に立てれれば幸いです。

明日の Go Advent Calendar 2016 は、 @yuin さんです。