REST APIドキュメント生成パターン

REST API用のドキュメントを生成するときにどうやってるかについて雑記を残しとく。

概要

実装とドキュメントの乖離を避けるためには、同じ意味情報を二箇所以上に定義することを避ける必要がある。そのための方法として、実装それ自身か、もしくは実装が参照している何らかのメタデータを元にしてドキュメントを生成したり、テストの実行結果からドキュメントを生成するというパターンがある。

テストから

Cookpadでは、autodocというライブラリを利用して、RSpecでテストを実行している途中で得られたメタデータからドキュメントを生成している。これはテストの実行結果からドキュメントを生成するパターン。

これは実現方法としてはかなり特殊な部類。このパターンが最も効果的に働くのは、ドキュメント生成のために余分な開発コストはあまり掛けたくないが、テストは真面目に書いている OR 真面目に書いてほしい、という場合。ドキュメントを生成するにはある程度仕様に関するメタデータが必要になるが、既存の実装からそういった類のメタデータを取り出すには、最初から意識して書いていない限り、そしてその意識をコードベース全体で統一させていない限り、かなり難しい。そういう場合でも何とかメタデータを得ようと思ったときに利用可能なのがテストケースから得られるデータで、完璧ではないにしろある程度使えそうなデータが得られる。

利点は、低コストでそれなりの情報が集められること・開発者がテストを書いてくれるようになること。テスト書こうね頑張ろうねみたいなことを言っても、実利的ですぐに得られるメリットが無いと人間は動かないので、テストを書けばAPIドキュメントが生成されるというのは効果がある。Cookpadでは旧APIのC0 Coverageは数十%だったけど、今のautodocを使うようになってからのAPIレイヤのC0 Coverageは (少なくとも自分が居た時点では) 100.0%だった。欠点は、完全な仕様に言及できないので雑なドキュメントになること。第三者に提供する公開API用のドキュメントとしてはいまいちだけど、内部の開発者用のドキュメントとして使うのには便利。

メタデータから

Qiitaでは、JSON Schemaという形式でAPIのインターフェースを定義している。このインターフェースを参照してAPIが実装され、同じくこのインターフェースを参照してドキュメントが生成されている。これはメタデータを元にしてドキュメントを生成するパターンの例。

利点は、汎用的な形式でインターフェース定義となるメタデータを用意すれば他の実装にも利用可能なこと。Ruby、JavaScript、Objective-C用のQiita APIクライアントは、JSON Schemaを元に生成されている。欠点は、インターフェース定義を書くのが手間なことと、メタデータを記述する形式の制約に縛られること。JSON Schemaは手で書くのが面倒で、自分はYAMLで書いたり、一部動的に生成したりしている。 この欠点には改善の余地があり、具体的には実装からも一部のメタデータを生成すれば良いという話で、次の節に書く。

実装から

Netflixは、Scalatra (=Scala界のSinatra) のソースコードを解析してSwagger用のドキュメントデータを生成している。これは実装それ自身を元にしてドキュメントを生成するパターンの例。他に、Grapeのように制約されたDSLのみを用いてAPIを実装し、DSLから得られたメタデータを元にドキュメントを生成するという例もある。

仕様が先か実装が先かという話で、この方法はメタデータからドキュメントを生成する方法と概念的に直交している訳ではない。けれど、出来れば実装からメタデータを生成して、そこからドキュメントを生成するというのが理想的だと自分は考えている。メタデータを書いてそれに合わせてAPIを実装するより、普通に(=開発者がそれが普通だと考えている方法で)APIの実装を書いて、書いた実装から勝手にメタデータが生成されて、そこからドキュメントが勝手に生成される、という方が良いと思う。

個人的な見方として、DSLを書くというのは、実装効率が良く、学習効率が悪い手法だと感じている。属人性が高まるんじゃないか・そのシステムを離れた後にチームメンバーが持ち帰れる知識が少ないんじゃないかという、茫漠とした不安がある。なので、メタデータを得るためにDSLを利用するよりも、ソースコードを解析して勝手にメタデータを生成してくれるという仕組みが実現できるとベストだと思う。この辺は個人によって意見が分かれるところで、未来の自分が手のひらを返して「DSL最高」とか「結論としてはケースバイケース」とか言ってる将来も見えるし、まあ今現在お前はそう考えているんだなというぐらいに捉えておいてもらえれば。

一方で、どんなコードを書き散らしても適当に解析して上手くいくように苦心するよりは、良いコードを書いたら良いドキュメントが生成される、という風にしておくのが丁度良いと思う。テストからドキュメントを生成するようにしたらテストを書くようになったという話も然り、機械も人間も読みやすいコードを書いていくべきだけど、そうすることで短期的にすぐメリットが享受出来るという実感がないと人間はやらないし、まあその辺の分かりやすい餌として便利なドキュメントが生成出来ますというメリットを謳って釣っていくのがいいと思う。

おわり

概念投げたら最高の具象になって返ってくる世界が最高。