ドキュメントエンジニアリングとAPIドキュメンテーション

はじめに

テクニカルライター(technical writer)という言葉を聞くと、ほとんど「ライター」という単語だけ見て「文章を書く人」と思いがちです。もちろん間違いではありません。しかし、実際にキーボードを叩いて文章を書く仕事は、テクニカルライター業務のほんの一部です。1日にどれくらい文章を書くか測定したことはないですが、テクニカルライターのトム・ジョンソン(Tom Johnson)によると、仕事をする時間の約10%が文章を書く時間だそうです。

では、その他の時間には何をしているのでしょうか。これもトム・ジョンソンによると、開発者のインタビュー、ほかの人が書いたドキュメントのレビュー、アプリの動作を録画するためにiPhoneの「脱獄」をする、MediaWikiにリンクされている画像にキャプションを入れる方法を探す、などの作業をしているそうです。その中で、私がここで説明したい内容は「iPhoneの脱獄」ではありません。結果的に、文章を書くこととは全く関係なさそうに見えるエンジニアリングについてです。

テクニカルライティングの作業をしていると、1回以上は下記のような依頼があります。

「技術情報を盛り込んだ200のテキストファイルを、1つのWordファイルにまとめてください」
「社内のWikiに掲載したものを、公式の開発者サイトにアップロードしてください」

このような依頼に対応できる方法はたった一つ、「コピペ(コピー&ペースト)」です。もちろん高度な知性を発揮して、何もない白紙に新しい文章を書かなければならないテクニカルライターにとって、まったく知性を発揮しなくてもいいこのような作業は、リフレッシュにもなるので1日くらいは費やす価値があります。しかし、1週間後に、同様の依頼がきてしまいます。

「テキストファイルを見てみたら、旧バージョンにのみ適用される内容がありました。200のファイルのところどころを修正したので、前回作ってもらったWordファイルに反映してください。一部のアップデートで済むと思います。」

依頼する側は「一部のアップデート」と言います。しかし、一部のアップデートには、うっかり漏れているところがあったり、ほかの文章にも影響を与える可能性があります。結局、もう一度全体的に検討が必要な仕事になります。私と同僚はこれを「内職」と称しました。テクニカルライターから言わせてもらえれば、そもそも、Wordファイルを更新してくれればいいのに、なぜかそのようにはいきません。なぜそのようにいかないかについては、ブログの分量制限もあるので説明できませんが、内職のような作業は繰り返されてしまいます。

何度か細かい手作業をしたら意欲にあふれていた新人のテクニカルライターは、Wordを作ったMicrosoftに対して、つい恨み節を吐きます。そして、怒りと恨みの段階を乗り越えたら、やっとドキュメントエンジニアに生まれ変わります。この流れがあるために、テクニカルライティングとドキュメントエンジニアリングは切っても切れない関係であると言えるでしょう。

私は、もともとツールを作って使うことが好きで、より早くドキュメントエンジニアの道に入り、今こうしてドキュメントエンジニアリングについて、ブログを書いています。ほかの人と比べると、Microsoftを恨む期間が少し短かったと思います。考えてみたら、テクニカルライターになって初めて任されたプロジェクトで、100余りのExcelファイルを1つのWordファイルにまとめる作業をしたのが、その道の始まりでした。当時のプロジェクトマネージャーも、やはり繰り返されるExcel-Word間のコピペが非効率的だと感じ、解決策を探しているところでした。私は、その作業を担当してOffice Open XMLを利用し、ExcelをWordに変換するツールを作りました。

最初は、ExcelをWordにダイレクトに変換しましたが、データバージョンの管理と双方向の変換が必要になりました。そこで、Excelデータを標準XMLに変換・保存した後Wordファイルに出力するように変えました。その後、私はエンジニアらしく、ドキュメントの自動生成、多様なフォーマットに対応できるドキュメント標準化に関心を持つようになりました。

ドキュメントエンジニアリングに属している作業はさまざまです。ドキュメンテーションのプロセスを構築し、プロジェクトの生成物を管理するのもドキュメントエンジニアリングの範疇です。この記事では私の関心分野であるドキュメントの変換と自動化に関してのみ書いてみます。

APIドキュメンテーション

テクニカルライティング業務の中で、APIドキュメンテーションは、ドキュメントエンジニアリングが最も多く適用される分野です。この記事で、API関連のドキュメントを扱うのもそのような理由からです。

APIドキュメント、主にAPIリファレンスと呼ばれるドキュメントは、プログラミングの歴史と共に存在してきました。気の合う友だち何人かとソフトウェアを開発していた時代、必ずしもテクニカルライターが一緒にいたとは思えないので、ほとんどはプログラマーが自分でAPIリファレンスを書いていたと思います。最初はテキストファイルで書いたと思いますが、ソースコードと同期することが難しく、ドキュメントを別途作成しなければならないので負担になったんでしょう。そのうち、ソースコードからAPIリファレンスを作成する方法が出てきました。

APIリファレンスは、開発文書によくある開発者ガイドとは少し違います。開発者ガイドは、内容の流れ(操作の流れ)が重要ですが、APIリファレンスはAPI同士の順番や関連性はほとんどありません。極端に言うと、1つのAPIの説明は、そのまま1つのドキュメントになるわけです。<図1>と<図2>で分かるように、開発者ガイドは説明文が長く続いています。一方、APIリファレンスは、各APIの役割のみを説明しています。もちろん、カテゴリーごとに分類して探しやすくなっています。

<図2>LINE SDK for iOS APIリファレンスの例(LineSDKJSONWebToken

APIリファレンスでは、ほとんどのAPIの説明方法は、とても似通っています。ライブラリーAPIやフレームワークAPIでは、関数(メソッド)名、説明、引数、戻り値という構造で、説明が繰り返されます。また、REST(Representational State Transfer)APIは、エンドポイント(endpoint)、説明、引数、レスポンスという構造で、説明が繰り返されます。このようにお互いに関連がなく、繰り返される構造を持っているドキュメントは、ツールを利用して作成しやすいと言えます。そのため、開発者ガイドを自動で作ってくれるツールはなくても、APIリファレンスを作ってくれるツールは以前から存在して今も発展を続けています。

1995年、サン・マイクロシステムズ(Sun Microsystems)がJavaと一緒に、ソースコードのコメントを利用してAPIドキュメントを作るJavadocを開発し、20年以上が経った今も広く使われています。Javadocの成功を受け、他のプログラミング言語もソースコードを利用した独自のドキュメンテーションツールを続々と開発しました。ソースコードを利用したものではありませんが、REST APIのためのドキュメンテーションツールとして「OpenAPI Specification(以下、OAS)」が提供されています。

APIリファレンスは必須なのか

この分野で数年間仕事をしている経験から、ドキュメントの中で開発者が最も多く見ているのはAPIリファレンスだというのは、かすかに感じていました。しかし、主観的に感じただけでそれを裏付けるデータはありませんでした。ところが幸いなことに、SIGDOCが実験にもとづいて定量的なデータを発表しました。母集団は小さいですが、このような種類の調査は多くないため、開発者が新しいAPIに出会ったときにどのような行動をするかについて理解するために、有用なデータであると思います。

SIGDOCが発表したデータを参考に<図3>を作成しました。これは、開発者が初めて接するAPIを利用して、問題を解決するときに、どこにどれだけの時間を使っているかを表しています。

<図3>問題を解決するために開発者が時間を使っていること(How Developers Use API Documentation: An Observation Study、SIGDOC)

最も大きな割合を占めている「Editor & Client」は、ドキュメントを見る以外の作業です。この項目を除けば、開発者がドキュメントを見るときに最も時間を使っていることは、APIリファレンスを読むことであるようです。そのため、人手も時間も足りなくてすべてのドキュメントを作成するのは難しいプロジェクトでも、最低APIリファレンスは作成したほうがいいと思います。せっかくなら使ってもらえるものを作ったほうがいいでしょう。幸いなことに、APIリファレンスは開発者が作成するに最も負担のないドキュメントです。いちいち全部書く必要もなく、決まっている内容を書くだけで、その役割を果たすことができます。

APIリファレンスには何を書くべきか

APIドキュメンテーションの依頼が来たら、普段、私は次の流れで作業します。

  1. APIの形式やプログラミング言語、出力フォーマットを確認する。
  2. 対応するツールを選ぶ。
  3. 1つのAPIを選んで説明のサンプルを作成する。
  4. どこに何を作成するべきかを説明するガイドを含めたテンプレートを作成する。
  5. 開発者にAPI説明の作成を依頼し、その内容を検討する。
  6. 全体のプロセスを検討し、ドキュメント作成を自動化する。

上記の5、6まで進めることができれば、この上ないドキュメントになります。しかし、プロジェクトの終了までテクニカルライティングを専任できない場合は、4までの作業をするだけでも、かなり満足できる結果を得られます。

1の作業が必要な理由は、APIの形式とプログラミング言語、出力のフォーマットによって、使うべきツールやガイドのテンプレートが変わってくるためです。例えば、Android向けライブラリーのAPIリファレンスをHTMLで作るためにはJavadocを使用します。また、Springで作成したREST APIリファレンスをWebサーバーで公開するためにはSwaggerを使用します。同様に、Pythonで作成したライブラリーのAPIリファレンスを電子bookで配布するためにはSphinxを使用することになります。

<コード1>は、APIリファレンスの生成ツールであるJavadocを利用する場合の例です。ソースコードコメントを利用しています。

<コード1>Javadocの例

/**
*私が作った本当に素晴らしいクラス
*@version 0.1
*/
public class MyFantasticClass {
/**
*与えられた値の2倍を計算する。
**整数ではない値の2倍を得るためには、see alsoにある項目を参照すること。
** @param base 2倍にしたい値。0から100までだけ入力できる。
* @return 与えられた値の2倍
* @see getDouble(float)
*/public int getDouble (int base) {
…(中略)
 }
}

IDE(integrated development environment)を使っていれば、通常はメソッドのプロトタイプを解釈され、@param, @returnなどの必要なタグが自動的に入力されます。このタグを見たら、開発者が入力すべき内容は何か分かります。このように決まったフォーマットに合わせて内容を入力するようにするのは、APIリファレンスツールの基本機能であり、使用する人が諦めないようにサポートする役割があります。テクニカルライターでさえ、白紙を前に何かを書こうとすると悩み、手は止まってしまいます。まして開発者に空っぽのテキストファイルを与えて何か書くようにしたらどうなるでしょう。もちろんうまく書ける人もいますが、普通は最初の文を始めるまでかなりの時間がかかると思います。決まったフォーマットにそって内容を埋め込むようにするのは短答式問題に似ていて、ドキュメントを作成するスピードがぐっと上がります。

この方法で、書くべき項目や何を書けばいいかを、開発者に伝えることはできます。しかし、各項目に必ず入るべき内容を書くようにするには、これだけでは足りません。4(テンプレートを作成する)の段階のように、ある項目にどのような内容を書き、どのような内容を書いてはいけないかを説明するガイドを含めたテンプレートを一緒に提供するのをおすすめします。テンプレートは、プログラミング言語またはAPIの形式によって違います。

<コード2>では、Javadocのテンプレートの例を紹介します。このようなガイドは、同様の構造を持っているほかのAPIにも適用できます。

<コード2>Javadocのテンプレートの例

/**
* 最初の文には、動詞を使用してメソッドの役割を説明してください。「何を返す」は避けてください。<p/> 
* 改行の後、下記のような情報があったら記述してください。 
* - このメソッドを呼び出す前後に、行うべき作業があったら記述してください。
* - 特定の状況で、このメソッドを使用してはいけないなら、その理由を説明してください。
* *参考*英語で書くときは、最初の文字は大文字で書いてください。
*
* @param base どんな意味のパラメータなのか書いてください。
* booleanの値なら、いつtrueで、いつfalseなのか書いてください。
* 数字なら、範囲があるか書いてください。enumなら、そのenum項目をリンクしてください。
* 許されていない値を送信すると、どんなことが起こるか書いてください。
* @return 何を返すか名詞で書いてください。
* booleanの値なら、いつtrueで、いつfalseなのか書いてください。
* 数字なら範囲があるか書いてください。enumなら、そのenum項目をリンクしてください。
* 問題が発生したとき、一般的な状況と違う意味の値を返すなら、それを記述してください。
* (例:-1を返す場合)
* @see 同様の機能をするメソッドがあったら記述してください。
* ある仕様を実装したものなら、その仕様の名前またはリンクを記述してください。
*/
public int getDouble (int base) {
…(中略)
 }
}

上記のテンプレートにも書きましたが、APIリファレンスで最もよく漏れている内容は、引数や戻り値の範囲です。戻り値が配列型であれば、どのような値を使えるか列挙します。戻り値が数字であれば、その範囲や値の意味をあわせて説明する必要があります。このような情報が漏れていると、APIリファレンスを見て開発する人が、無用な試行錯誤をしなければいけないためです。

したがって、漏れがないように注意を促す内容を含めたテンプレートを提供すれば、はるかに速くて正確なAPIリファレンスを作成できます。こうして作成された内容をJavadocで出力すると、<図4>のようなAPIリファレンスが生成されます。

<図4>Javadocの出力の例(LINE SDK v5.0.0 for Android

ガイドを含むテンプレートがなくてもツールを利用してこのような状況を防げるのでしょうか。ソースコードのコメントによるツールからさらに発展したのが、API仕様書を利用するOASというツールです。OASの主な目的はドキュメンテーションではなく、設計およびテストなので、APIを定義するときにAPIが使用するオブジェクトを明確に入力することをおすすめします。

例えば、オブジェクトのフィールドがenumの場合は、あらかじめenumスキーマを定義してから、オブジェクトのフィールドではそのenumスキーマを参照します。また、オブジェクトのフィールドが数字であれば、最大値と最小値を入力して範囲を指定します。このようなテンプレートにしても、必ず開発者に範囲を指定してもらえるとは言えませんが、他のツールに比べて範囲の指定が漏れる頻度を減らすことができます。

APIリファレンスをどう届けるか

APIリファレンスを生成するツールのほとんどは、HTMLを出力する機能があります。オープンソースプロジェクト、特に専任のテクニカルライターがいないプロジェクトでは、このようなツールを利用して作ったHTMLファイルをGitHub Pagesなどにアップロードすることで十分です。しかし、開発者をサポートするための公式のWebサイトを持っている会社であれば、状況は少し違います。CMS(content management system)のようなWebコンテンツ管理ツールを使って、公式のWebサイトを構築したり、README.ioApiaryのような開発文書に特化したドキュメントサービスを使っている会社もあります。もちろん、独自で制作したWebサイトを使用している会社もあります。どちらにしても、<図4>のような見た目のAPIリファレンスをそのまま公式の文書にするのは難しいと思います。技術的な難しさもありますが、政策的な難しさが大きいでしょう。

Googleが提供するAndroid APIリファレンスだけ見ても、以前はJavadocのドックレット(doclet)であるDoclavaを使用して提供していましたが、現在は独自のツールに替えています。ソースコードのコメントに記述したAPI説明を見ると、独自のツールもJavadocを参考にしていると想像できます。

<図5>Android APIリファレンスの画面

Microsoftはどうでしょう。Microsoftは、IT企業の中で技術文書をオープンソース化した代表的な企業です。GitHubにあるAzureの技術文書をよく見てみると、REST APIを独自で定義したYAML形式1で記述したものが確認できます。Azureの公式Webサイトは、このデータ情報をAPIリファレンスとして提供します。

<図6>Azure APIリファレンスの画面

Azureのドキュメントのリポジトリから確認したYAMLデータは、以下の<コード3>です。

<コード3>Azure APIリファレンスの説明ファイル

- uid: azure-arm-sql.JobVersions.get
name: 'get(string, string, string, string, number, Object)'
children: []
type: methodlangs:- typeScript
summary: Gets a job version.
syntax:
content: >-
function get(resourceGroupName: string, serverName: string,
jobAgentName: string, jobName: string, jobVersion: number, options?:Object)
parameters:
- id: resourceGroupName
type:
- string
description: >
The name of the resource group that
contains the resource. You can obtain this value from the Azure
Resource
Manager API or the portal
....(中略)

オープンソースプロジェクトであるEnactも、ドキュメントをGitHubに公開しているので、どのようなツールを使用したのか推測できます。EnactのJavaScriptのAPIリファレンスは、JSDoc形式でソースコードに記述し、独自のツールを経てWebサイトに掲示する方式です。

<図7> Enact APIリファレンスの画面

AndroidとEnactはソースコードのコメントを使用し、AzureはYAML形式を使用しました。方式が違う理由は、使用するプログラミング言語とAPIの種類(例:ライブラリーAPI、フレームワークAPI、REST API)によって、広く使われるツールが異なるためでしょう。どのようなツールを使うとしても、ツールで生成したドキュメントを会社の公式Webサイトに簡単に統合できることがとても重要です。

JavadocとJSDocは出力を簡単にカスタマイズでき、AzureはOASに似ている独自のAPI仕様書を使っているため、公式Webサイトにふわさしい出力に変えることができます。つまり、3つの例すべてが、公式Webサイトにうまく溶け込むようなツールあるいは方法を選択したと言えるでしょう。

データで語るべきエンジニアが言うことではないかもしれませんが、正直言って外に公開するドキュメントは見た目も重要です。見た目がきれいで美しいドキュメントは、文章を読む前から読者の興味と信頼を得られるためです。もちろん中身もきちんとしている必要はありますが、そもそも見た目が企業のイメージに合わなかったり、アマチュアのように見えたら中身を読む前から信頼度が落ちるはずです。

このような理由で、私は外に公開するドキュメントを作成する場合は、JavadocやDoxygen、Swaggerなどが提供する標準のデザインを使用しないことをおすすめします。標準のデザインは会社のブランドアイデンティティーを盛り込みにくく、それまで会社が積み重ねてきた信頼感をドキュメントにまで伝えることができません。個人的には、所属している会社が、ドキュメントエンジニアリングについての技術や関心がないと誤解されるのでは?という恐れがあると考えています。

APIリファレンスは、APIを使用する開発者が最も多く見ているドキュメントで、ドキュメントエンジニアリングをどのように行うかによって、作成時間や出力の形が大きく変わります。このような理由で、専門のテクニカルライティングチームを保有している会社であれば、独自のAPIドキュメンテーションのソリューションを持つべきだと思います。まったく新しいツールを作るべきだと言っているのではなく、既存のツールを使用するとしても、トレンドの変化に合わせて正確かつ専門的な結果を出すソリューションを持つべきです。Googleも持っていますし、Microsoftも持っています。また、LINEも独自のAPIドキュメンテーションのソリューションを構築しようとしています。

良いAPIリファレンスソリューション

では、良いAPIリファレンスソリューションとはどんなものでしょうか。前述の例から2つの条件が分かります。

  • 出力形式が変わっても、すぐ適応できること。
  • 作成する人が、何を書けばいいかすぐ分かること。

Android開発者サイトは、何度もリニューアルされています。しかし、APIリファレンスは見た目が変わっただけで、ソースコードにJavadocで説明を作成する方式は変わっていません。ソースコードに作成した内容をWebページに変換する際、Googleが使用したツールがWebサイトの変化にすぐ適応できることを表しています。

Android開発者サイトの例から分かるように、APIリファレンスが公開されるWebサイトの見た目は、いつでも変わる可能性があります。Webサイトではなく、PDFのようなファイルで配布されることもしばしばあります。「腕時計からでもインターネットに接続できる時代にPDFだと?」と戸惑う人もいるかもしれませんが、開発現場ではまだPDFが多く使われています。不特定多数ではなく特定グループだけに配布するドキュメントや、公式Webサイトでの公開前に配布するドキュメントが、PDFを使用する例です。

もちろん時間がたてば、PDFで配布していたドキュメントをWebサイトで配布する可能性が高くなります。最初はドキュメントをPDFで配布し、数か月後にはWebサイトで公開するドキュメンテーションプロジェクトを私も何度か経験しました。そのため、新しいプロジェクトでマネージャーがAPIリファレンスはPDFで配布すると宣言しても、テクニカルライターはWebサイトでの配布を念頭に置いて作業をした方が良いでしょう。

出力形式の変化に素早く対応するためには、データ(内容)とビュー(出力形式)を分離するのが基本です。データには、太字などのインラインフォーマット以外は、段落全体の文字の大きさのような出力形式に関する情報を含めてはいけません。また、ビューはデータに盛り込まれている情報をどのように出力するかを表し、さらに出力形式を簡単に変更できる必要があります。このようにデータとビューを分離してから、どこに何を書けばいいかを明示的に表す構造で記述すれば、良いAPIリファレンスソリューションの2つ目の条件を満たせます。

Javadoc、JSDoc、OASに似ているYAML形式のどの方式でも、データとビューを分離し、明示的な構造でデータを作成するようにしました。

上で紹介したとおり、3つともテキストベースでAPIの説明を作成し、そのデータに適切なビューを適用して、HTMLファイルを生成します。

前述したツールが対応しないもの、例えば、C++で作成したAPIやgRPC APIは、APIリファレンスをどのように作成すればいいでしょうか。正直に言うと、両方ともサードパーティーのAPIリファレンス作成ツールがあるので、大した問題にはなりません。しかし、さらに一歩踏み出して、1つのプロジェクトでさまざまなプログラミング言語やさまざまなAPIリファレンスを提供することを考えてみましょう。プログラミング言語ごとにそれぞれ違うツールを使用したら、プロジェクト全体のAPIリファレンスはそれぞれ違う形になるしかありません。このようなケースまで考慮すると、良いAPIリファレンスソリューションの条件を、もう1つ追加する必要がありそうです。

  • さまざまなプログラミング言語やAPIの種類(例:ライブラリーAPI、フレームワークAPI、REST API)に関わらず、統合できること。

APIリファレンスソリューションのユースケース

良いAPIリファレンスソリューションに向けた3つの条件を達成するために、<図8>のようなAPIリファレンスソリューションを考えてみました。

<図8>良いAPIリファレンスソリューションの条件を達成するためのAPIドキュメンテーション作業の流れ

<図8>のデータの枠内に注目してください。ソースコードのコメントを利用した既存のドキュメントツールがある場合は、既存のツールを利用してソースコードからMarkdownファイルを生成します。既存のツールがない場合は、API specのようなテキストベースの独自の技術フォーマットからMarkdownファイルを生成するツールを開発します。独自の技術フォーマットといっても、構造化データを表現するためによく使用されるXML、JSON、YAMLなどの形式を使うと良いでしょう。ソースコードやAPI specに書いたAPIのデータから、Markdownのタグをつけた状態で出力されます。タグをどのようにつけるかは、この後で説明するテンプレートを利用します。使用するテンプレートの言語は、もっとも都合の用意ものを探してみてください。私は、ソースコードやAPI specからMarkdownを出力する際に使用するテンプレートを、「APIリファレンステンプレート」と呼ぶことにしました。

私が進めているプロジェクトでは、すべてAPIリファレンステンプレートを適用しました。残念ながらまだ公開していないプロジェクトであるため、この記事に書くことはできません。

この記事では、C++ベースのライブラリーAPIとREST APIを提供する仮想プロジェクトを使用して、APIリファレンステンプレートとは何かを紹介します。テクニカルライターのもとに届いたときは、ライブラリーAPIの説明はソースコードのコメントに記述され、REST APIの説明は社内のWeb掲示物に記述されていました。

<コード4>仮想プロジェクトのC++ライブラリーAPIの説明

namespace mine
{
/**
* 私が作った完璧なC++クラス。
* 生成後には必ず`CallMe()`を呼び出す必要があります。
*/
class MyClass
{
public:
/**
* 用事があったら電話してほしいという関数。
*/
void CallMe(void);
/**
* 私の質問に回答するようにする関数。
* @question 私がした質問。Nullなら必ずfalseを返します。 
* @return 質問に対する応答。応答が「その通り」ならtrue、「そうではない」ならfalseを返します。
*/
bool AnswerMe(char *question);
…(中略)
 };
}
<図9>仮想プロジェクトのREST APIの説明

<図9>の内容 :
OAS를 흉내낸 자체 API 템플릿을 사용해서 REST API 문서를 만들었습니다. → OASを参考にした独自のAPIテンプレートを使用し、REST APIドキュメントを作りました。
사용자 정보 조회 ➝ ユーザー情報の取得
사용자 정보 변경 ➝ ユーザー情報の変更
다음 중 하나여야 합니다. ➝ 以下のいずれかが返されます。 
상세한 결과 설명이 들어갑니다. ➝ 結果の詳細が返されます。
주어진 아이디(user_id)의 사용자 정보를 조회합니다. 요청이 성공적으로 서버에 전달되면 200 OK를 반환하며, 요청 처리 중 발생한 오류는 응답 객체의 resultCode 필드에 나타납니다. 공용 응답 필드를 참고하십시오. ➝ 与えられたID(user_id)のユーザー情報を取得します。リクエストに成功すれば、200 OKが返されます。リクエスト処理中にエラーが発生した場合は、レスポンスオブジェクトのresultCodeフィールドで結果が返されます。詳細は、共通レスポンスを参照してください。
조회할 사용자 ID. 사용자 ID는 사용자 목록에서 확인할 수 있습니다. ➝ 情報を取得するユーザーのID。ユーザーIDはユーザーリストから確認できます。
HTTP Result Code가 200 OK일 때 반환하는 정보입니다. ➝ HTTPコードとして、200 OKが返されたときの情報です。

私の作業は、2種類のAPIリファレンスを統合して、同じ形式でWebサイトにアップロードすることです。まず、現状を分析してどのツールを使用するか考えてみましょう。

ライブラリーAPIは、ソースコードに説明を作成したので、データをビューから分離している状態です。REST APIは、社内の掲示板に書いたので、データとビューが混在しています。私は、まずソースコードに作成したライブラリーAPIのデータを出力するビューテンプレートを作成し、次に社内の掲示板に作成したREST APIの説明からデータを抽出してまたビューテンプレートを作成します。最後に、2種類のAPIのビューを1つのドキュメントに統合します。

<表1>APIリファレンスのテンプレートを適用する仮想のプロジェクトの状態

項目ライブラリーAPIREST API
原本(開発者がデータを書いた場所)C++ソースコードのコメント社内の掲示板
データとビューの分離分離未分離
適用可能な既存のツールDoxygenの使用可能なし

<表1>から分かるように、プログラミング言語から独立しているドキュメンテーションツールであるDoxygenを使用して、C++ソースコードのコメントに作成したデータから、APIリファレンスを作成できます。DoxygenでHTMLファイルを生成することもできますが、Doxygenはカスタマイズが難しいうえに、私たちの目的は個別のHTMLを提供することではなく、統合HTMLを提供することです。したがって、Doxygenで直接HTMLを生成する代わりに統合しやすいフォーマットで作ることにします。

社内の掲示物で作成したREST APIの説明は、頻繁に変更されるとアップデートが非常に不便です。そのため、REST APIの説明は思い切って手動でデータを抽出し、YAMLで再作成します。社内の掲示物として共有しなければならない場合は、このYAMLファイルを共有できます。そして、それぞれのデータを1つのドキュメントに統合するためには、前述のようにHTMLではなく、統合しやすいフォーマットを使用する必要があります。ここでは、その中間段階の出力フォーマットとしてMarkdownを選択しました。

C++ライブラリーのAPIリファレンス作業

まず、ソースコードにあるライブラリーAPIの説明コメントをMarkdownに変換しましょう。Doxygenは、Markdownの出力には対応しないけど、独自で定義したXML形式でAPI仕様書を作ることができます。このAPI仕様書には、ソースコードを除いた純粋なAPI説明だけが入ります。

<図10>Doxygenの実行画面

<図10>のようにDoxygenのオプションで、XMLを出力するように設定して、ビルドします。次に、XMLをさまざまな出力にしてくれるMoxygenというツールを利用して、Doxygenで出力したXMLをMarkdownに変換します。

<コード5>C++ライブラリーAPIコメントのデータをMarkdownに変換した結果(中間段階の出力)

# class `mine::MyClass` {#classmine_1_1MyClass}
私が作った完璧なC++クラス。
生成後には必ず[`CallMe()`](api-CallMe.md#classmine_1_1MyClass_1a20213a9d29c24324d6ea32a0010d3e9f)を呼び出す必要があります。
## Summary
Members | Descriptions--------------------------------|---------------------------------------------
`public void `[`CallMe`](#classMyClass_1adc72431f56d6803585f60cef6e467991)`(void)` |用事があったら電話してほしいという関数。
`public bool `[`AnswerMe`](#classMyClass_1a98aecda3ae776dd1f99aad5f9990ff62)`(char * question)` |私の質問に回答するようにする関数。
...(中略

Moxygenもビューテンプレートをカスタマイズできるので、必要に応じて出力を修正できますが、今回の仮想プロジェクトではMoxygenの基本テンプレートを使用します。

次に説明するREST APIリファレンスの出力結果が、Moxygenの基本テンプレートに似ている形式になるようにカスタマイズします。

REST APIリファレンス作業

REST APIの説明は<コード6>のようにYAMLフォーマットで、手動で再作成します。前の例に出ているAzureのドキュメントの方法に似ています。

<コード6>REST APIをYAML形式で作成したもの

summary:ユーザー情報の取得
path: /user/{user_id}
method: GET
description: |-
与えられたID(user_id)のユーザー情報を取得します。
リクエストがサーバーへの送信に成功すれば200 OKを返し、リクエスト処理中に発生したエラーは
応答オブジェクトの`error`フィールドに出ます。
parameters:
 - name: user_id
 in: path
 description: |-
取得するユーザーID。ユーザーIDは[ユーザーリスト](/apis/user-list)から確認できます。
 required: true
 response:
 header:
 description: |-
HTTP Result Codeが200 OKのときに返す情報です。[共用応答フィールド](/apis/response-common-fields)を参照してください。
 body_segments: 
 id:
 description: |-
パラメータで受信した`user_id`
 required: true
 type: string
 name:
 description: |-
ユーザー名
 required: true
 type: string
 image:
 description: |-
ユーザーの写真が保存されているURL
 required: false
 type: object
...(中略)

パッと見ると、かなりOASに似ています。ただOASは、すべてのAPIを一気に記述し、レスポンスコードによってより詳しい説明があります。一方、このYAMLフォーマットでは、1つのAPI仕様書に1つのAPIのみ記述し、応答も「200 OK」に限定しました。

もちろん、各プロジェクトの特性に応じて形式を変更できます。

このようにテキストでREST APIの説明を記述すれば、ソースコードと一緒にGitのリポジトリでバージョンを管理できるというメリットがあります。また、APIを追加したり修正するときもこの形式に合わせて作成すればいいので、社内の掲示物で作成する場合より固定的なデータ構造を維持できます。つまり、決まっている形式とは異なる任意のテーブルや画像を、誰も入力できないことを示しています。

今度はこのYAMLデータをMarkdownに変換する作業が必要です。Markdownで、どのようにタグを付けるかを決めなければいけません。前述のとおり、C++ライブラリーのAPIリファレンスの中間段階の出力と同様のレイアウトにします。テンプレート言語として、Handlebarsを使用することにしました。

<コード7>REST APIのYAMLデータをMarkdownに変換するテンプレート

...(中略)
## Summary
Members | Descriptions---------------------------|---------------------------------------------
{{#each paths}}{{toUpperCase method}} {{path}} | {{summary}}
{{/each}}
{{#each paths}}
## {{#if summary}}{{summary}}{{/if}} `{{toUpperCase method}} {{path}}` {{#if operationId}}{{addId operationId}}{{/if}}
{{description}}
{{! parameters }}
### Request parameters
{{#if parameters}}
Parameter | Type | Description
:--------------:|-------------|------------------------------------------
{{#each parameters}}
`{{name}}`<br/>({{in}}) | {{schema.type}} {{#if schema.items}} of {{schema.items.type}}{{/if}} | {{description}} {{#ifCond required "true"}}O{{/ifCond}}
{{/each}}
{{else}}None{{/if}}
...(中略)

YAMLファイルを読んで、HandlebarsのAPIテンプレートファイルを適用すれば、<コード8>のようなC++ライブラリーのAPIリファレンスに似たような出力が得られます。

<コード8>REST APIのYAMLデータをMarkdownに変換した結果(中間段階の出力)

## Summary
Members | Descriptions---------------------------|---------------------------------------------
GET /user/{user_id} |ユーザー情報の取得
## ユーザー情報の取得`GET /user/{user_id}` 
与えられたID(user_id)のユーザー情報を取得します。
リクエストがサーバーへの送信に成功すれば200 OKを返し、リクエスト処理中に発生したエラーは、応答オブジェクトの`error`フィールドに出ます。
### Request parameters
Parameter | Type | Description
:----------------:|-------------|---------------------------------------------
`user_id`<br/>(path) | |取得するユーザーID。ユーザーIDは[ユーザーリスト](/apis/user-list)から確認できます。
...(中略)

独自のAPIテンプレートファイルを実装する方法は、この記事のテーマから離れますので、触れません。そのかわりに、GitHubリポジトリの説明とコードを参照してください。

統合APIリファレンス

ここまでの作業で、Markdownのフォーマットは同じで、出力形式が似ている2種類のAPIリファレンスを出力できました。ここからは、2種類のAPIリファレンスを統合して(以下、統合APIリファレンス)公式のWebサイトに入れたり、Jekyllのような静的サイトの生成ツールを利用して、独自のWebサイトを読者に提供しましょう。<図11>は、フォーマット変換ツールであるPandocとそのHTMLテンプレートの中の1つを利用し、統合APIリファレンスのWebページを作成した画面です。

<図11>統合APIリファレンスのWebページ

<図11>の内容 :
내가 만든 완벽한 C++ 클래스. ➝  私が作った完璧なC++クラス。
생성 후에는 반드시 `CallMe()`를 호출해야 합니다. ➝  生成後には必ず`CallMe()`を呼び出す必要があります。
용건 있을 때 전화해달라는 함수. ➝ 用事があったら電話してほしいという関数。
내 질문에 대답하게 하는 함수. ➝ 私の質問に回答するようにする関数。
내가 한 질문. null이면 반드시 false를 반환합니다. ➝ 私がした質問。nullだったら必ずfalseを返します。
질문에 대한 응답. 응답이 ‘그렇다’면 true, ‘아니다’면 false를 반환합니다. ➝ 質問に対する応答。応答が「そうだ」ならtrue、「違う」ならfalseを返します。
OAS를 흉내낸 자체 API 템플릿을 사용해서 REST API 문서를 만들었습니다. → OASを真似した独自のAPIテンプレートを使用し、REST APIドキュメントを作りました。
사용자 정보 조회 ➝ ユーザー情報の取得
사용자 정보 변경 ➝ ユーザー情報の変更

中間段階の出力としてMarkdownを使用すれば、HTMLだけでなく、よりさまざまなファイルフォーマットに変換できます。<図12>は、その中の1つであるPDFファイルです。

<図12>統合APIリファレンスのPDF

<図12>の内容 :
내가 한 질문. null이면 반드시 false를 반환합니다. ➝ 私がした質問。nullだったら必ずfalseを返します。
OAS를 흉내낸 자체 API 템플릿을 사용해서 REST API 문서를 만들었습니다. → OASを真似した独自のAPIテンプレートを使用し、REST APIドキュメントを作りました。
사용자 정보 조회 ➝ ユーザー情報の取得
사용자 정보 변경 ➝ ユーザー情報の変更
주어진 아이디(user_id)의 사용자 정보를 조회합니다. 요청이 성공적으로 서버에 전달되면 200 OK를 반환하며, 요청 처리 중 발생한 오류는 응답 객체의 error 필드에 나타납니다.  ➝ 与えられたID(user_id)のユーザー情報を取得します。リクエストがサーバーへの送信に成功すれば200 OKを変換し、リクエスト処理中に発生したエラーは 応答オブジェクトのresultCodeフィールドに出ます。
조회할 사용자 ID. 사용자 ID는 사용자 목록에서 확인할 수 있습니다. ➝ 情報を取得するユーザーのID。ユーザーIDはユーザーリストから確認できます。
HTTP Result Code가 200 OK일 때 반환하는 정보입니다. 공용 응답 필드를 참고하십시오. ➝ HTTP Result Codeが200 OKのときに変換する情報です。共用応答フィールドを参照してください。
파라미터로 수신한 user_id ➝ パラメータで受信したuser_id
사용자의 이름 ➝ ユーザー名
사용자의 사진이 저장된 URL ➝ ユーザーの写真が保存されているURL
성공 예제: ➝ 成功例
주어진 아이디(user_id)의 사용자 정보를 변경합니다.  ➝ 与えられたID(user_id)のユーザー情報を変更します。
변경할 사용자 정보입니다. User Info를 참고하십시오.  ➝ 変更するユーザーの情報です。User Infoを参照してください。

<図12>のように見栄えのいいPDFを作るためには、LaTeXを使用します。PDFを出力する方法についてはこの記事で扱っていないので、興味がある方はLaTeXを調べてみてください。

まったく別のAPIリファレンスを統合する必要がなくても、さまざまなファイルフォーマットに対応するためにMarkdownを中間段階の出力として使用することはいい方法です。前述のとおり、PDFを配布した後、Webサイトに掲示するドキュメントにこの方法を使用すると、Webサイトがいつ公開されることになってもすぐに対応できます。

おわりに

APIリファレンスを作成するときの重要な要素を紹介し、それを満足させるAPIリファレンスソリューションを見てみました。一見、複雑で大変に見えるかもしれませんが、このすべてをスクリプトで一気に作業できます。このようにプロセス化したドキュメント作業では、Jenkinsのような継続的インテグレーションツールを利用すれば、データ(ソースコードあるいはYAMLファイル)を変更するときに自動的に最終出力物(HTMLまたはPDF)を作成できます。はじめに一度設定しておけば、手間がかかることはあまりありません。

Doxygenのように広く使われるAPIリファレンス生成ツールの中を見てみると、ソースコードのコメントからデータを抽出し、ユーザーが変更できるビューにデータを入れることで、出力形式をカスタマイズできるようになっています。Doxygenの場合は、すべての作業が隠れているため複雑に見えないだけで、実際はこの記事で紹介した方法と、大差ないことを行っています。しかし、依然として複雑に見えるのなら、プロジェクトの特性に応じて中間段階の出力を生成する段階や、YAMLによるAPI仕様書を作成する段階を省略することもできます。

この記事の目的は、必要以上に複雑なプロセスを適用することを勧めるためではありません。APIリファレンスをより簡単に作成して管理するための1つのソリューションを紹介したい、というのが目的です。

この記事を読んでいる方は、今後APIリファレンスの生成ツールを選ぶ際に、下記の2つを必ず考慮してください。

  • データとビューを分離できるか。
  • ソースコードと一緒にバージョン管理できるか。

1つ目については、本文で長く説明したのでこれ以上言わなくていいでしょう。2つ目については、この記事で詳しく触れなかったんですが、テキストベースのAPI技術を適用すれば簡単に達成できます。

この記事のAPIリファレンスのテンプレートで紹介した、YAMLで記述するAPI仕様書は、上記の2つの考慮事項を満たすツールの1つです。ソースコードのコメントからのドキュメンテーションツールがないプログラミング言語を使用したり、ソースコードがまだなかったり、ソースコードの修正をためらうプロジェクトにAPIリファレンスソリューションを適用するために便利なツールです。より専門化された統合APIリファレンス生成ツールが発表されるまでは、前述の問題でAPIリファレンスの作成に苦労している方には、有用な解決策になると信じています。

参考資料

  1. YAMLは、XML、C、Python、Perl、RFC2822で定義されている電子メールのフォーマットからヒントを得て作られた「人間にとって読みやすい」データ直列化フォーマットです。