JSONスキーマにサーバ側APIについての記述を書けたり、ソースコードが生成できたりするので、いろいろ試してみました。
今回行ったことは次の通りです。
- IIJmioクーポンスイッチAPIのドキュメントを参考に、JSONスキーマを勝手に書いた
- JSONスキーマ用のツールprmdでAPIドキュメントを作成したり、スキーマの検証を行った
- JSONスキーマ用からGo言語のクライアントコードを生成するツールschematicでコードを生成して、それを使った
prmdを導入する
とりあえず、JSONスキーマ用のツールprmdを導入しておきます。gemで一発です。
$ sudo gem install prmd
JSONスキーマを記述する
IIJmioクーポンスイッチAPIを参考に、JSONスキーマを書いてみました。
prmd
に雛形を作成する機能があるので、それを利用して書いていきます。
$ mkdir schemata $ prmd init base > schemata/base.json
3つのAPIしかないとは言え、JSONスキーマの仕様について調べながらなので書くのに時間がかかりました。
- Understanding JSON Schema: わかりやすいJSONスキーマの解説
- JSON Schema and Hyper-Schema: JSONスキーマの仕様のドラフトなど
なお、prmd
でのスキーマを書く作法的には、メンテナンスしやすいように、APIを機能ごとファイルを分けるように書くとよいみたいです。
基本的には、definitions
あたりにデータやパラメータの定義を書いておき、properties
にAPIの戻り値オブジェクトの定義を書き、links
にそれが返されるAPIの定義を書く、という感じみたいです。
"$ref": "/foo/bar#/hoge/fuga"
みたいなのはJSON Pointerというもので、
この場合は、idが/foo/bar
なオブジェクトの["hoge"]["fuga"]
なオブジェクトを参照するということを意味しています。
ちなみに、既存のサービスとして、Google APIやHeroku Platform APIではAPIにJSONスキーマが用意されているので、それを見て参考にしたりしました。
これらは、例えば次のようにしてJSONスキーマを取得できます (Googleのはブラウザで直接見ることもできます)。
curl https://api.heroku.com/schema -H "Accept: application/vnd.heroku+json; version=3" curl -O https://www.googleapis.com/discovery/v1/apis
prmdでAPIドキュメントを作成する
JSONスキーマを書き終えたら、まずprmd
で分割したファイルを結合して、ひとつのスキーマにします。
$ mkdir gen $ prmd combine --meta meta/meta.json schemata > gen/schema.json
なお、meta.jsonは次のようなファイルです。
$ cat meta/meta.json { "description": "IIJmio Coupon API", "id": "iijmio", "links": [{ "href": "https://api.iijmio.jp/mobile/d/v1", "rel": "self" }], "title": "IIJmio" }
続いて、作成されたスキーマが正しいか検証してみます。
$ prmd verify gen/schema.json
エラー報告がなければドキュメントを生成してみましょう。
$ prmd doc gen/schema.json > gen/schema.md
これで生成されたドキュメントはこちら。
Attributesのあたりがやたら見づらいですが、それっぽい感じのドキュメントになっています。
schematicでGoのクライアントコードを生成する
最後に、Go言語のJSONスキーマ用ツールschematicでクライアントコードの雛形をつくって、それを利用してみましょう。
まず、schematicをてきとうに導入します。
$ git clone https://github.com/interagent/schematic.git $ cd schematic $ go build cmd/schematic/schematic.go
schematic
の使いかたは、schematic foo.json > foo.go
でよいのですが、日本語コードが入っているとエラーになるようなので、次のようにてきとうに取り除きました。
$ mkdir -p src/iijmio $ schematic =(sed -E 's/"description":.+//' gen/schema.json) > src/iijmio/iijmio.go
そして、生成されたコードがそのままでは利用できないので、を次のように修正しました。
time
パッケージがなぜかimportされているが、不要なのでコメントアウトしたVersion
が空文字なので入れておいたreq.Header
にX-IIJmio-Developer
とX-IIJmio-Authorization
を入れておいた- コードでは
Get
がトップレベルがリストであるデータ取得を想定しているが、クーポンAPIではそうではないので、リストを取らないようにした
具体的な修正内容はこのコミットを見てください。
あとは、これを利用するメインコードを書いて終わりです。
package main import ( "iijmio" "fmt" ) func main() { mio := iijmio.NewService(nil) cs, err := mio.CouponList(nil) fmt.Println(cs, err) ps, err := mio.PacketList(nil) fmt.Println(ps, err) }
これを実行すると次のような感じで出力されます (実際にはインデントや改行は入りません)。
&{[ {[{0xc208249140 bundle 1420} {0xc208249160 bundle 2000} {0xc208249180 topup 0} {0xc2082491a0 topup 0} {0xc2082491c0 topup 0} {0xc2082491e0 topup 0}] hddzzzzzzzz [{[{<nil> sim 1}] true hdoxxxxxxxx GDxxxxxxxxxxxx yyyyyyyyyyy false false false}] Minimum Start} {[{0xc208249330 bundle 120} {0xc208249350 bundle 2000} {0xc208249370 topup 0} {0xc2082493a0 topup 0} {0xc2082493c0 topup 0} {0xc2082493e0 topup 0}] hddxxxxxxxy [{[{<nil> sim 6}] true hdoxxxxxxxy DNxxxxxxxxxxxxy yyyyyyyyyyz false true true}] Minimum Start}] OK} <nil> &{[ {hddxxxxxxxx [{hdoxxxxxxxx [{20141006 33 0} {20141007 64 0} {20141008 60 15} : ]}] Minimum Start} {hddxxxxxxxy [{hdoxxxxxxxxy [{20141006 0 0} {20141007 0 0} {20141008 0 0} ]}] Minimum Start} ] OK} <nil>
ちなみに、クーポン利用状態変更については、できるかどうか確認していません。というか、メソッドCouponChange
を呼ぶためのコードが私には書けませんでした。
func (s *Service) CouponChange(o struct { CouponInfo []struct { HdoInfo []struct { CouponUse bool `json:"couponUse"` HdoServiceCode string `json:"hdoServiceCode"` } `json:"hdoInfo"` } `json:"couponInfo"` }) (*Coupon, error) { var coupon Coupon return &coupon, s.Put(&coupon, fmt.Sprintf("/coupon/"), o) }
おわりに
JSONスキーマをつくって、そこからGo言語コードを自動生成してみました。
JSONオブジェクトを定義するだけではなく、REST APIをより詳しく定義したい場合にはSwaggerというものもあるみたいです。swaggerの仕様にはREST API向けの属性がいろいろ定義されているので便利そうです。
また、今回はJSONスキーマを手書きで書きましたが、ソースコードから自動生成するというアプローチもあるみたいです。例えば、Go言語のbeego Webフレームワークを利用していたら、コードのコメントからSwaggerのスペックファイルを生成したりできるようです。
関連リンク
- Safx: MacでGoのデバッグ環境を構築する
- Safx: Go言語のBDDテストツールGoConveyを使ってみる
- IIJmioクーポンスイッチAPI
- interagent/prmd · GitHub
- interagent/schematic · GitHub
- Schemataのドキュメント
- Understanding JSON Schema — Understanding JSON Schema 1.0 documentation
- JSON Schema and Hyper-Schema
- draft-ietf-appsawg-json-pointer–07 - JavaScript Object Notation (JSON) Pointer
- Swagger: A simple, open standard for describing REST APIs with JSON | Reverb for Developers
- Getting Started - Google APIs Discovery Service — Google Developers
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。