[1] [[Web API]] ([[HTTP]] による [[API]]) の悪い設計例やどう設計するべきかの指針のご紹介です。

[138] 何が良いかは[[諸説]]あり[[宗教的]]で難しいですが、
悪いものには悪い理由があるので賛否はともかく参考になるはずです。

* バージョニング (版付け)

[2] [[API]] にバージョンを設けるべきではありません。 [[API]] の拡張は、常に[[後方互換性]]を保った形で行うべきです。

[3] 従って [[URL]] や [[HTTPヘッダー]]などにバージョン番号を指定させる必要はありません。

[7] やむを得ず非互換変更せざるを得なくなった時は、非互換な機能のみ、
新しい[[エンドポイント]]を設けるべきです。はじめから非互換変更するつもりで準備しておくのは無駄ですし、
非互換変更するための言い訳を用意するようなもので、危険です。

[38] バージョンが複数あるということは、同じものを複数メンテナンスし続けなければならないということです。バグやセキュリティーホールのリスクも増えます。場合によっては、混用された時におかしなことにならないかも注意しなければなりません。

[39] 実際それはつらいので、いつか古いバージョンへの対応をやめようとします。しかし、古いバージョンで問題なく使えていたクライアントは、無駄な変更コストが発生しますし、それによって新たにバグが生じることもあります。面倒に思ったり、コスト上の理由などで、それを機に対応を取りやめるクライアントもあるかもしれません。旧バージョンのアクセスが減ったと思って廃止したら、アクセス頻度が低いクライアントが利用できなくなって困る、というのもありそうです。 
バージョンを分ければ変更しやすくなるというのはその場しのぎでしかなく、
問題は先送りされているだけです。

[88] 結局、[[API]] 提供者にとっても、クライアント開発者にとっても、クライアント利用者にとっても、嬉しいことは何一つありません。

;; [40] シェアを背景に [[API]] の非互換変更を頻繁に行う [[Facebook]] や [[Twitter]] は、雇用創出のための公共事業で仕様変更をやってるのではないかと揶揄されていますよ。
サーバー側がクライアント側より著しく高い政治力を持つ時だけうまく(?)いくモデルで、
参考にするべきではありません。

[EG[
[121] あるサービスでは、バージョン番号として[[日付]]を指定させています。
そのドキュメントには「現在の日付を指定するな」とわざわざ注記があります。

クライアント開発者にとっては自分の書いたコードが1日でも長く無メンテナンスで使い続けられるのが良いですから、
現在の日付を指定したくなるのもわかります。そのような注記が必要だということ自体、
この方式が失敗していることを象徴しています。
]EG]

;; [122] [[バージョニング]]は、 [[Web]] の他の分野でも[[アンチパターン]]として知られています。

* 特殊な要求メソッド

[4] 実用上、 [CODE(HTTP)@en[[[GET]]]] と [CODE(HTTP)@en[[[POST]]]]
(と [CODE(HTTP)@en[[[OPTIONS]]]] と [CODE(HTTP)@en[[[HEAD]]]])
以外の[[要求メソッド]]を使うべきではありません。

[6] 意味的にもすべての操作をこの2つで十分明確に表現できます。

[79] [CODE(HTTP)@en[[[PUT]]]] や [CODE(HTTP)@en[[[DELETE]]]] を使うべきだというのは宗教的な主張なので、
普通は [CODE(HTTP)@en[[[POST]]]] で問題ありません。
最近は [CODE(HTTP)@en[[[PATCH]]]] 教も人気ですが、
流行に乗ればいいというものでもないでしょう。

[5] 特殊な[[要求メソッド]]に対応していない[[クライアント]]のための代替手段として
[CODE(HTTP)@en[[[X-HTTP-Method-Override:]]]] [[ヘッダー]]に[[要求メソッド]]を指定できるようにすることがありますが、
本末転倒です。正しい[[要求メソッド]]を使うべきです。

-*-*-

[32] [[安全]]で[[冪等]]な操作にしか [CODE(HTTP)@en[[[GET]]]] を使う(使える)べきではありません。
かつては [[JSONP]] のためやむを得ず [CODE(HTTP)@en[[[GET]]]] を使うことがありましたが、
今やただの[[セキュリティーホール]]です。

* 特殊な認証方式

[8] [[認証]]には [[HTTP]] [[基本認証]]か [[OAuth 2.0]] [CODE(HTTP)@en[[[Bearer]]]]
を使うべきです。いわゆる[[APIキー]]認証は [CODE(HTTP)@en[[[Bearer]]]]
で表現できます。 ([[OAuth 2.0]] の[[認可フロー]]を実装しなくても、
[CODE(HTTP)@en[[[Bearer]]]] だけ使えます。)

[31] [[キャッシュ]] ([[サーバー]]アプリケーションを構成する[[プロキシ]]、
または[[クライアント]]が使っている[[プロキシ]]のもの。) による問題を防ぐためには、
[[HTTP認証]]の仕組みに乗るべきです。その意味で [[query]] や独自
[[HTTPヘッダー]]に[[APIキー]]を指定する方法は、安全ではありません。

[129] [CODE[Bearer]] と実質的に同じものなのに、独自の [CODE[auth-scheme]]
名としている [[Web API]] もありますが、何のメリットもありません。避けるべきです。


[80] 独自の[[署名]]を求める方式も、避けるべきです。歴史的には意味があったかもしれませんが、
今や [[HTTPS]] が基本ですから、本当に[[署名]]が必要な状況は稀です。
[[署名]]はデバッグが難しく、開発者を悩ませてきました。

* パスの濫用

[21] [[URL]] の [[path]] の濫用は慎むべきです。

[22] 例えば検索キーワードなどは [[URL query]] で指定するべきです。

[23] [[path]] に任意の文字列が指定可能な場合、 [[クライアント]]側の[[パーセント符号化]]漏れ、
[[Web API]] サーバー側の[[逆プロキシ]]や [[WAF]] の設定ミスによる[[パーセント符号化]]まわりの不具合などが起こりがちです。

[35] [[path]] に任意の [[URL]] を埋め込めるのは、特に避けるべきです。

* 動詞のパスを頑なに拒む

[34] よく [[path]] は[[名詞]]がよく、[[動詞]]は好ましくないと言われます。

[48] ただし整理上の都合で[[動詞]]を使った方が綺麗になるなら、無理に避けるものでもありません。
たとえば [CODE[https://host/document/124345]] の編集に関する操作は
[CODE[https://host/document/124345/edit]] への [CODE(HTTP)@en[[[POST]]]] に、
削除に関する操作は
[CODE[https://host/document/124345/delete]] への [CODE(HTTP)@en[[[POST]]]]
に実装しても何ら問題ないでしょう。

;; [CODE[https://host/document/124345/edit]] の [CODE(HTTP)@en[[[GET]]]] が編集ページ、
[CODE[https://host/document/124345/delete]] の [CODE(HTTP)@en[[[GET]]]]
が削除確認ページになっていると、ちょうど良い。

[65] [[動詞]]を避けることで直感的でなくなったり、複雑になったりするのでは本末転倒です。

[73] >>72 も参照。

* 何でもパスに入れたがる

[66] オプションを[[引数]] ([[URL query]] や[[要求本体]]の 
[CODE(MIME)@en[application/x-www-form-urlencoded]])
ではなく[[パス]]の一部に入れたがる人もいるようです。

[67] あまりどちらを使うべきか一概に言えるものでもないのですが、
次のような判断基準はたてられそうです。
[FIG(list)[
- [68] 省略可能なオプションなら、[[引数]]で指定させた方が良い。
- [69] 値が長くなりそうなオプションなら、 [[引数]]で指定させた方が良い。
- [70] 操作対象を指定する性質が強そうなオプションなら、[[パス]]に入れて良い。
- [71] いくつかのオプションがあって自明な順序がない 
(包含関係やユーザー○○の投稿××のような親子関係がない) なら、
[[引数]]で指定させた方が良い。
- [72] 動作の指示は[[引数]]で指定させた方が良い。
- [74] 記号を値に含むなら (特に、普段は含まないがたまに含む場合)、
[[引数]]で指定させた方が[[パーセント符号化]]を忘れるミスは防ぎやすい。
]FIG]

* 用語が一貫していない

[81] [[API]] に登場する語 ([[path]] の一部分、[[引数]]の名前、
[[列挙型]]の[[引数]]の値、 [[JSON]] の[[オブジェクト]]に含まれる名前など)
は、一貫した命名規則に従うべきです。

[EG[
[82] 例えば、[[利用者]]のことを表すのに、 [CODE[user]]、[CODE[usr]]、[CODE[u]]、
[CODE[account]] のような似て非なる語・綴りを混在させるべきではありません。
]EG]

[83] [[省略形]]よりも[[完全形]]の方がわかりやすくて良いとする人もいます。
しかしやたらと長い方がかえってわかりにくくなったり、面倒くさかったりもします。
省略するべきかどうかは適宜判断すればよく、語の長さよりも一貫性の方が重要でしょう。

[93] [[英単語]]を連ねる場合、 [[camelCase]]、 [CODE[-]]、[CODE[_]]、[CODE[.]]、
区切りなしなどいくつかの流儀があります。[[プログラミング言語]]の変数名などと同じく、
色々な人が色々な好みを持っていて、どれが優れているというものでもありません。
これもまた、一貫性を持たせることさえ心掛ければ、どの方法でも良さそうです。

;; [98] たぶん、これは [[Web API]] に限らず、開発プロジェクト全体で用語集を使って統一した方がよいでしょう。

* 変な状態符号

[11] [[状態符号]]は適切に選択するべきです。エラーなら [CODE(HTTP)[[[4xx]]]]
とするべきです。

;; 決め方に迷ったら [CODE(HTTP)[[[4xx]]]] 参照。

[47] エラーだろうがなんだろうが構わず [CODE(HTTP)[[[200]]]] を返すものは最悪です。
本文 [[JSON]] データでエラーを表している場合でも、適切な[[状態符号]]を使うべきです。

[128] [[ライブラリー]]によっては[[状態符号]]で正常かエラーかを判断したり、
開発者に有用なデバッグ用メッセージを生成したりといった機能があります。
これは[[応答]]がおおよそどのような性質のものであるかを[[状態符号]]という
[[HTTP]] 全体で共通の方法で伝達できることの恩恵です。
たとえ詳細なエラーを別の方法で伝える必要があるとしても、
それはそれとして、[[状態符号]]は正しく設定するべきです。

* 変なプロトコル

[94] 一昔前、 [[XML-RPC]] や [[SOAP]] が若干流行ったことがありました。
しかし今では誰も使っていません。

[95] [[WebDAV]] や [[Atom API]]・[[AtomPub]] が使われたこともありました。
今でも皆無ではありませんが、新規開発なら気にする必要はありません。
既存サービスとの互換性のようなことも、考えるだけ時間の無駄でしょう。

** 意味のない互換性

[96] [[Web API]] のやり取りを共通化する[[プロトコル]]はこの他にも色々と提案されてきましたが、
どれも大きな成功を収められていません。 [[Webアプリケーション]]はそれぞれに異なる要件と利用形態を持っていて、
どれだけ共通化しても、どうしても収まりきらない部分が出てきてしまいます。
するとサービスごとに独自対応せざるを得なくなりますが、
それならば初めからそれぞれの特性や利用方法に応じた独自の
[[API]] とした方が、提供側も利用側も楽だったりするのでしょう。
[[HTTP]] を使う、 [[JSON]] を使うといった基盤といえる部分を除けば、
[[Web API]] の[[プロトコル]]は[[標準化]]には馴染まなそうです。

[EG[
[97] [[Twitter]] と [[Facebook]] は、扱うデータの形態や[[利用者]]のアクションだけみれば
[[API]] を共通仕様に揃えられそうなものですが、
両者の実際の [[API]] の[[エンドポイント]]や[[データ構造]]は全く異なります。
設計思想や歴史的な経緯の違いももちろんあるのでしょうが、
同じように見えても実際には全然異なる機能だったり、
違った形で利用されていたりして、簡単に共通化できるものでもなさそうですし、
それが各サービスの差別化要素にもなっているのでしょう。
]EG]

[41] 競合他サービスの [[API]] に似せた [[API]] を提供しようとして、失敗している例をたまに見かけます。

[42] 完全互換ならクライアント開発者のメリットも多いでしょうが、実際には細かな差異がたくさんあったり、他サービスの仕様変更に追随できなかったりして、似て非なるものになっているのが普通です。すると他サービス用のコードを思ったほど流用できなかったり、境界ケースで正しく扱えず不具合が生じたりしがちです。

[44] 困るのは互換性があると信じて有名競合サービスとそれに似せた弱小サービスに対応した[[クライアント]]の開発者です。
有名競合サービスが仕様を変更し、弱小サービスが追随できない場合、
細かな分岐を増やすなり、コードを丸々コピーするなりしてがんばって両方への対応を維持し続けるか、
弱小サービスのサポートを終了するか、
弱小サービスのことを忘れていて仕様変更対応後に不具合が出てから気がつくか。
それならはじめから別のサービスは別のコードで実装していた方が良かったのではないでしょうか。

[43] クライアント開発者の視点からすると、 (対象となるサービス自体のデータモデルが似ていることが前提で) 同じ操作が似たような手順で実行さえできればよく、そのエンドポイント名や引数名、応答のデータ構造などは (完全に一致しないなら) 合わせなくても良いように思えます。

** HTTPS を使っていない

[29] 常に [[HTTPS]] を使う[SHOULD[べき]]です。[[平文のHTTP][素のHTTP]] 
が好ましい理由は何もありません。
歴史的な理由で未だに [[HTTP]] で [[Web API]] を提供するサービスも少なくありませんが、
それに倣うべきではありません。

;; [30] 両方を提供する理由もありません。ただの[[セキュリティーホール]]です。

[99] [[iOSアプリ]]から利用する場合、 [[ATS]] により標準で [[HTTPS]]
のみ有効になっています。アプリに設定を変更させるのは危険であり、避けるべきです。

* 変な出力データ形式

** 変なデータ形式

[9] 出力データ形式は [[JSON]] を基本とするべきです。
ほとんどの[[プログラミング言語]]や[[フレームワーク]]で、
[[JSON]] は標準で実装されています。

[33] [[XML]] は追加ライブラリーが必要で面倒なクライアント環境やデータの扱いが面倒なライブラリー
[[API]] が多いので、極力避けるべきです。

[50] [[CBOR]] や [[MessagePack]] のような[[バイナリー]]ベースの形式を好む人もいます。
確かにサイズは抑えられ、 (実装次第ですが) [[JSON]] より高速に処理できるかもしれませんが、
ほとんどの場合は微々たる差で、より広く普及していてデバッグも容易な [[JSON]]
の方が適切です。少なくても不特定多数の開発者に公開された [[API]]
では、 [[JSON]] を基本とするべきです。

[12] [[JSONP]] は使うべきではありません。ただの[[セキュリティーホール]]です。
異なる[[起源]]の [[JavaScript]] からのアクセスが必要なら、 [[CORS]]
を使うべきです。

** 内容折衝

[10] データ形式を選択制にするときは、[[URL query]] または[[拡張子]]で指定できるようにするべきです。
[CODE(HTTP)@en[[[Accept:]]]] による選択は使うべきではありません。
杜撰な[[キャッシュ]]の実装は [CODE(HTTP)@en[[[Accept:]]]] を正しく扱えません。
[[URL]] で指定できる方が[[デバッグ]]が容易です。
[[サーバー]]の[[アクセスログ]]に普通 [CODE(HTTP)@en[[[Accept:]]]]
は記録されないので、[[URL]] に含めた方が便利です。

[49] [[Webブラウザー]]向けと [[Web API]] で同じ [[URL]]
を使い [CODE(HTTP)@en[[[Accept:]]]] によって[[内容折衝]]するような実装方法もありますが、
混乱を招くだけで誰も得しないので、避けるべきです。

** エラー応答の形式

[36] クライアントが機械的に処理することを想定したエラー応答は、
[[JSON]] など (成功時と同じ) 機械可読な形式で提供するべきです。例えば投稿エンドポイントは、
投稿エラーなら、投稿エラーを説明した [[JSON]] 応答を返すべきです。

[37] しかしだからといって、無理にどんなエラーでも [[JSON]]
で返すようがんばる必要はないでしょう。例えばアプリケーションサーバーが過負荷で応答できないときの[[リバースプロキシ]]のエラーまで敢えて
[[JSON]] にしなくても構いません (しても構いませんが)。どうせクライアントは[[状態符号]]以上の有益な情報をその応答から得られません。
クライアントはどのみち [[JSON]] でない時のエラー処理を実装しておく必要がありますから、
実装の手間も変わりません。

* 変な MIME 型

** 独自の MIME 型

[123] [[JSON]] の [[MIME型]]は [CODE(MIME)@en[application/json]] です。
ほとんどすべての場合、これをそのまま使って何の問題もありません。

[124] たまに、 [CODE(MIME)@en[[[application/]][VAR[service-name]][[+json]]]]
のような独自の [[MIME型]]を使っていることがあります。 [[MIME型]]は独自なのに、
データは普通の [[JSON]] だったりします。 [[MIME型]]の仕組みとして間違ったことではありませんが、
何のメリットもない、意味のないことです。

;; [125] [[ライブラリー]]によっては、 [[MIME型]]が [CODE(MIME)@en[application/json]]
の時 [[JSON]] を扱いやすい機能を提供しているのに、独自の [[MIME型]]が使われるため、
その便利機能が使えないという可能性もあります。

** MIME 型引数

[78] [[MIME型]]の[[引数]] ([CODE[application/example; foo=bar]] の [CODE[foo=bar]]
のような部分) を使いたがる人がいるようです。一見便利に使えそうな場所ですし、
実際意味的に適切な場合もあるのですが、 [[MIME型]]の[[引数]]の取扱いは[[相互運用性]]に欠けるので、
あまりおすすめできません。

;; 実装によって、[[引数]]の存在に対応していない、大文字と小文字の扱いが不適切、
複数の[[引数]]の指定順序の違いが不適切、
同名の[[引数]]が複数あるときの扱いがわからない、
値の特殊文字や[[非ASCII文字]]の符号化の方法が混乱している、
といった色々な問題があります。

[142] [[Web API]] の [[versioning]] に濫用した事案:
[CODE[application/vnd.elasticsearch+json]]

* JSON データ構造

[45] [[JSON]] の場合、最上位は ([[配列]]や[[プリミティブ値]]ではなく)
[[オブジェクト]]とした方が無難です。何かのリストを返したい時も、
後から他の付加データを増やしたいときに[[配列]]だとどうしようもないので、
[[オブジェクト]]でくるんでおくと良いでしょう。

[46] [[識別子]]などで桁数の多い[[数字]]列を扱う時は、 [[JSON]]
の[[数値]]ではなく[[文字列]]で表すように注意するべきです。

;; [[JavaScript]] では構文解析時に32ビット整数に丸められてしまいます。

[118] [[JSON]] の [CODE[null]]、[[ブール型]]、[[数値]]、[[文字列]]の違いは、
[[プログラミング言語]]によっては区別されないことや違いが曖昧なことがあります。
従って、これらの違いを厳密に扱うことを要求するべきではありません。

[EG[
[119] 例えば、[[クライアント]]から [CODE[{"foo": [[true]]}]] または
[CODE[{"foo": [[false]]}]] のような値を受け取りたい場合、
[[JavaScript]] の [CODE[ToBoolean]] の挙動に寄せて、

- 次のいずれかの場合は[[偽]]
-- [CODE[foo]] が指定されていない
-- [CODE[foo]] が [CODE[false]]
-- [CODE[foo]] が [N[0]]
-- [CODE[foo]] が[[空文字列]]
- それ以外の場合は[[真]]

... のようにすると、いろいろな[[プログラミング言語]]の[[ライブラリー]]から無理なく扱えて好ましいと思われます。
(更に [[Perl]] の [[bool context]] の挙動に寄せて、[[文字列]] [CODE[0]]
も[[偽]]とみなすのもありかもしれません。)
]EG]

[51] [[HAL]] のような [[JSON]] ベースの言語を採用したり、
[[JSON Schema]] のような[[スキーマ]]に従って定義したりすることを好む人もいます。
そうしたものが有用な場面もあれば、あまり意味のない場面もありますから、
個別の用途に合わせて何を採用するか決めるべきです。「すべて○○を使うべき」
といった主張は眉唾物です。

* 変なタイムスタンプ

[13] [[日時形式]]は、[[Unix time]] を基本とするべきです。
[[ISO 8601の日時形式]]や[[HTTPの日時形式]]、その他独自の形式は、
構文解析や生成処理や[[時間帯]]処理が面倒でミスを誘発しがちなので、避けるべきです。

* HTTP ヘッダーの濫用

[24] [[HTTPヘッダー]]の濫用は避けるべきです。

[25] [[クライアント]]による[[ページング]]の指定は、 [[URL query]] で行うのが伝統的な方法です。
それで何も問題ありません。

[26] [[サーバー]]による前後のページのリンクなどは、本文 [[JSON]] データに含めるべきです。
[CODE(HTTP)@en[[[Link:]]]] [[ヘッダー]]による指定は構文解析や生成処理が面倒でミスを誘発しがちなので、避けるべきです。
本文に含められない時は、 [[URL]] だけを値とする独自の [[HTTPヘッダー]]を使うのが次善策です。

* 変なページング

[76] 「投稿一覧」や「コメント一覧」のような追加や削除が起こり得る対象の一覧を時刻順で取得する
[[API]] では、[[ページング]]にページ番号や先頭からの位置を取得するべきではありません。
最初のページと次のページの取得時点で位置が変化している可能性があるので、
項目の重複や欠落が発生する可能性があるからです。

[77] 「時刻 [VAR[t]] より前、後」のような指定形式が良さそうですが、
同時刻に複数の項目が存在するかもしれないケースでは、
取り扱いが難しくなるかもしれません。
[[マイクロ秒]]や[[ナノ秒]]の精度の時刻を使えば、そのようなケースはほとんど排除できそうです。
[[秒]]の精度では、重複はかなりの頻度で発生します。

* 人間向けサーバーと API サーバー

[57] 人間向けサーバーと [[Web API]] のサーバーをどのように共存させるかは、
[[アプリケーション]]の実装手法や[[サービス]]の規模と[[負荷分散]]の戦略によって、
いろいろな手法が考えられます。実際、いろいろな方法が用いられています。

[58] 例えば:
[FIG(list)[
- [59] [CODE[https://service/page]] ([[HTML]]) と [CODE[https://service/page.json]] (API)
のように[[拡張子]]で区別する
- [60] [CODE[https://service/api/page]] のように [[API]] を特定の[[ディレクトリー]]に収容する
- [61] [CODE[https://www.serivce.example/page]] と [CODE[https://api.service.example/page]]
のように[[ホスト]]で区別する
]FIG]

[62] 最初は小規模のサービスが大きくなった場合でも、 [[URL]] で区別できるなら、
[[リバースプロキシ]]で接続先[[アプリケーションサーバー]]を切り替えられますから、
[[負荷分散]]戦略によって [[URL]] の設計を過剰に制約する必要はありません。

* 困ったドキュメント

[14] [[人間]]による明確なドキュメントを提供するべきです。

[15] 機械的に生成されただけのものは、ドキュメントとは言えません。
むしろドキュメントを整備した気になるだけなので有害です。

[EG[
[27] 例えば [[JSON Schema]] から機械的に生成した [[HTML]]
ファイル群は、ただの [[JSON Schema]] の[[書き下し文]]であって、
[[ドキュメント]]ではありません。
もしや有用な情報が含まれているのでは、と読者の期待を煽ってしまうだけなので、
むしろ有害です。
]EG]

[16] 入出力や処理内容など必要な情報を過不足なく記述するべきです。
エンドポイントごとに一言コメントを並べたようなものは、メモ書きであり、
ドキュメントではありません。

[17] また例示は例示であり、ドキュメントの本編ではありません。
例示をいくつ並べても、エンドポイントの説明とはいえません。

[EG[
[52] 有名な [[Webサービス]]の [[Web API]] であっても、
[[応答]]の [[JSON]] の実例を示しただけでまともな説明を加えていない「ドキュメント」
しか無いことがあります。
]EG]

[131] 主要な[[プログラミング言語]]での利用例を示すこと自体は構いませんが、
[[HTTP]] でどのような[[要求]]を送信すると、どのような[[応答]]を受信することになるか、
という説明を怠ってはいけません。 
[[クライアント]]がどのような[[プログラミング言語]]でどのような[[ライブラリー]]を用いていようと、
[[HTTP]] という共通の[[プロトコル]]で等しく [[API]] にアクセスできることが、
[[Web API]] の特徴であり、[[可能性]]です。


[28] [[API]] によってアクセスされる対象であるオブジェクトの説明をがんばっているのに、
肝心の [[Web API]] の部分、つまり [[HTTP]] でどのような[[要求]]が必要で、
どのような[[応答]]が送られるのかの説明が雑なことがよくあります。
サービスのオブジェクトモデルの説明は、もちろん重要な情報ですが、
それだけでは [[Web API]] のドキュメントになりません。

[63] 一読して理解できないレイアウトは避けるべきです。 API ドキュメントは、
デザイナーやエンジニアの自己表現の場ではありません。

[102] 表示上の固定部分 ([CODE[position: fixed]] など) はできるだけ避けるべきです。
[[ノートPC]]などの狭い[[画面]]や、広い[[画面]]でも開発中の[[アプリケーション]]の[[窓]]や[[エディター]]の[[窓]]などと同時表示している場合など、
狭い表示領域しか与えられないことがあります。

[132] 同じ理由で、本文の左右に目次や例示などで広い幅を占有する領域を配置するのは避けるべきです。

[100] 無駄にページ分割された構成は、一見整理されて使いやすく思えますが、
どんな機能があるか全体像をよく理解していない API 利用者にとっては望む機能がどこにあるか探しにくかったりします。
少ないページにまとめられていた方が、どんな機能が提供されているのか眺めやすいです。
例えば[[エンドポイント]]ごとに別ページに分かれていたりすると、
極めて使いづらいドキュメントになります。

[101] 同じような理由で、見出しをクリックすると詳細説明が展開されるような、
一々細かく操作しないと全体を読めないドキュメントも使いづらいです。

[141] 
一つの [[Web頁]]に内容がまとまっていれば、
[[Webブラウザー]]の標準のページ内検索機能で求めるものを見つけることができて、
便利なのです。

-*-*-

[103] 本サイトへのリンクがどこかにあるべきです。
([[ドキュメント]]トップページへのリンクがあっても本サイトへのリンクがない (かわかりにくい)
ことは意外とよくあります。)

[EG[
[104] 例えば採用サービス候補がいくつかあって比較しているときなどに、
[[API]] ドキュメントと本サイトの機能ガイド、価格表などを行き来したいことがままあります。
]EG]

-*-*-

[139] 
[[Webブラウザー]]の[[Web頁]]内検索を呼び出そうと [KEY[Ctrl]] + [KEY[F]]
を押すと、キャンセルして独自の検索機能を表示するドキュメントがあります。
ほとんどすべての場合、
[[Webブラウザー]]標準の検索機能の方が優秀なので、邪魔なだけです。
([[Webブラウザー事業者]]で勤務するトップクラスの技術者が時間をかけて作ったものと、
どちらが便利か、少し考えればわかりますよね。)

[140] ドキュメント (複数の [[Web頁]]) の横断検索は、あれば便利なので、
別にフォームを用意して貰えればそれで良い。
[[Webブラウザー]]の標準機能を潰す必要はどこにもない。


** ドキュメント自体の URL

[110] 他の[[開発者]]との情報交換や、
[[ソースコード]]の[[コメント]]などの形でドキュメントの一部を参照したいことがよくあります。
従って、

- [111] [[ドキュメント]]の [[URL]] をころころと変えるべきではありません。
新機能の追加などのタイミングでドキュメントを再編したくなるかもしれませんが、
元の [[URL]] で新しい場所に簡単にたどり着けるような配慮は絶対に必要です。
[WEAK[(わかりやすいように再編すること自体は問題ありません。)]]
- [113] 1つの[[文書]]の内容が多岐にわたる場合は、
項目ごとに [[ID]] を付与するべきです。
特に[[エンドポイント]]や[[データ型]]などは、
個別に参照したくなりそうなので、個々に [[ID]] を付与することが望ましいです。
できれば、章見出しをリンクとしたり、「§」マーク等でリンクしたりして、
読者が容易に気づけるようにするべきです。
- [112] [[文書]]の途中にリンクされた時の [[JavaScript]] による[[スクロール]]効果など、
読者が求める情報に到達するまでに無駄な時間を浪費する機能を盛り込むべきではありません。
- [114] [[フレーム]]や、[[素片識別子]]の[[リンク]]を使わない [[JavaScript]]
による[[スクロール]]・表示切り替えのような、
[[アドレスバー]]の表示と実際の[[文書]]の [[URL]] が異なってしまう技術を使うべきではありません。
- [115] [[スクロール]]に追従して、あるいは[[クリック]]等の動作で、
勝手に [[URL]] (の[[素片識別子]]) を書き換えるのは避けるべきです。
一見便利機能のようですが、読者が共有したいと思った [[URL]] がいつの間にか違うものに書き換わっていたりして、案外不便です。

** ドキュメントのプロトコル

[107] [[ドキュメント]]は [[Webサイト]]で簡単に参照できるようにしておくべきです。

;; [[ダウンロード]]できるようにしても構いませんが、必須ではありません。

[108] [[素のHTTP]]ではなく、[[HTTPS]] で提供するべきです。

;; [109] [[Web API]] 本体が [[HTTPS]] なのに[[ドキュメント]]だけ[[素のHTTP]]
のサービスがありますが、なぜそうしようと思ったのか理解に苦しみます。
今となっては[[素のHTTP]]で提供するのが妥当である理由は何もなく、
サービス提供者の技術力の低さを露呈するだけです。

** エンドポイント

[130] [[API]] の [[URL]] の [[path][URL path]] 部分しか示していないドキュメントをたまにみかけますが、
[[scheme][URL scheme]] や[[ホスト]]も含めてすべて示すか、
その説明に[[リンク]]するべきです。なぜなら、
読者 (開発者) は望む機能を探してエンドポイントの説明ページを見て、
それをもとにコードを書くので、その時必要な情報がそこにすぐにあるべきだからです。

[135] 驚くべきことに、ドキュメントのどこにも書かれていないサービスすら存在します (!)。
API 提供者は一度でもその API を実際に使って何かを作ってみようとしたことがあるのでしょうか。
(自分達は API を使わずになんでもできてしまうので、意外となかったりします。
しかしそんな態度で果たして使いやすい API が提供できるかどうか。)

** 値域

[84] 可能な値の範囲は、できるだけ明確に文書化するべきです。その際は、
将来の拡張も視野に入れ、限定しすぎず、かといって一般化もしすぎず、
適当な粒度とするべきです。

[EG[
[85] 例えば、あるサービスの[[利用者]]の[[識別子]]を [[API]] でやり取りする場合、
おそらく[[クライアント]]もその識別子を何らかの形で保存しなければなりませんから、
[[ストレージ]]上の[[データ型]]を決めなければなりません。
識別子が[[数値]]なのか[[文字列]]なのか、含まれる文字の種類は何なのか、
最大の長さはどれだけなのか、といった情報が[[クライアント]]側開発者には有用です。

[86] ここで、[[サーバー]]側で識別子を32ビット整数型で表現しているとしても、
これをそのまま文書化することが望ましいとは限りません。将来の拡張の余地を残すため、
64ビットで表現可能な非負整数、と説明した方が良いかもしれません。

[87] 加えて、[[利用者]]の識別子は[[利用者]]によって互いに異なること、
決して他の[[利用者]]に再割当てされることがないこと、
といった性質も、説明しておくのが良さそうです。
一方で、識別子は小さい順に連番で割り当てられる、という情報は書かないべきでしょう
([[クライアント]]側で有用な情報ではなさそうですし、将来サーバー側で割当方法を変更したくなるかもしれません)。
]EG]

[116] 「数値」や「[[タイムスタンプ]]」や「[[ISO 8601の日時形式]]」のような曖昧な説明ではなく、
「1個[[以上]]の[[ASCII数字]]列によって表される[[十進整数]]」、
「[CITE[HTML Standard]] が規定する[[妥当な大域日時文字列]]」
などの明確な説明とするべきです。

現実には残念ながらこれを怠る解説が少なくありません。
例えば「[[ISO 8601の日時形式]]」は無数の細かな選択肢がありますが、
それをすべて受け入れていることはほとんどありません。
技術ドキュメントは、異なる背景をもつ技術者同士が曖昧なく意思疎通できなければ意味がありません。

[117] 例示は、説明したことにはなりません。ドキュメントから例示をすべて取っ払ったときにも、
曖昧無く理解可能に記述するべきです。例示は理解の補助に過ぎません。

** ドキュメントのライセンス

[133] [[クライアント]]の開発者が[[ドキュメント]]の一部を[[コメント]]として[[ソースコード]]に書き込んだり、
提示されたサンプルコードを改変して利用したりすることは、よくあります。
これを安心して行わせるために、[[ドキュメント]]は自由度の高い[[ライセンス]]で提供するべきです。

[134] 具体的には、 [[CC0]] や [[MITライセンス]]や [[Apacheライセンス]]が適切と思われます。

** コピペ可能性

[136] ドキュメント中の重要な部分は、一般的な [[Webブラウザー]]で[[利用者]]が簡単に[[コピペ]]できる状態になっているべきです。

[EG[
[137] ある [[Webサービス]]の[[ドキュメント]]は、
[[エンドポイント]]の [[URL]] をクリックすると詳細が開いたり閉じたりする形になっています。
[CODE[details]] [[要素]]に相当するものですが、独自実装で、
テキストを選択しようとすると開いたり閉じたりして、選択は解除されてしまいます。
ドキュメントを読む人が、書かれている情報をどう利用するだろうか、
というところにもう少し想像力を働かせるべきでした。
]EG]

* 開発環境がない

[18] 提供されるサービスの性質次第ではありますが、[[クライアント]]の開発者が利用できる開発環境が提供されていると大変有用です。

[20] [[課金]]など重大な処理が伴うものや、通常のサービス利用では前提条件を構築するのが難しい処理などは、適当な開発環境が用意されているべきです。

[19] [[API]] の[[ホスト]]を書き換える程度の手間で本番環境と切り替えられるのが理想的です。

[53] 有料サービスや審査制のものなどでは、開発者が容易にアクセスできる開発を提供することはとても重要です。
本格的な開発 (や契約その他) の前の評価段階の予備的開発のため、
特別な審査や費用などがなくても利用できるようにするべきです。

* API の設計ガイドライン

[54] [[プログラミング言語]]や[[ライブラリー]]と同様に、 [[Web API]]
にもこう設計するのが良い、悪いというような[[指針]]や[[コーディング規約]]のようなものが色々とあります。

[55] そうした指針類は、設計に迷った時のヒントとして有用かもしれませんが、
あまり意識しすぎても、無駄な制約でかえって開発しづらくなったり、
設計を歪めたりする危険性があります。

[56] 宗教性の高い指針には、特に自分の信仰と親和性が高そうに思った場合を除き、
従わない方が無難です。

[EG[
[64] [[パス]]などで[[単数形]]にするか、[[複数形]]にするか: 
どうでも良い。好きにすれば良い。その場その場で不自然でないようにすれば十分。
]EG]

[89] 有名[[サービス]]が採用している方針が、
常に好ましい方針とは限りません。真似る場合には、
自身の開発する対象にあわせて適切かどうかを都度検討するべきです。
長く続く有名サービスほど、歴史的な事情が積み重なっているはずです。
当該サービスの開発者自身も、おそらく何らかの不満を持っていることでしょう。

[90] 「宗教性」は、馴染みの薄い人には感じ取りにくいかもしれませんが、
次の各項に該当するなら要注意です。

- [91] やたらと 「[[REST]]」 を強調している。 (00年代後半から10年代前半の流行語。)
- [92] 「[[URI]]」が云々と言っている。 ([[URI]] は [[URL]] を意味する00年代の流行語。)
- [75] 「[[ベストプラクティス]]」などと称する指針は、
その[[著者]]の思想が色濃くにじみ出た「ベスト」であると思って注意して読むべき。
いつでもどこでも誰でも「ベスト」な方針が存在するのなら、既にみんなそれに従っているはずで、
そうでないからこそ「ベスト」とわざわざ主張しているのである。
- [105] やたらと「すべて」、「必ず」のような強い要求をしている。 
- [120] 特定の手法を「美しい」などと謳っている。

[106] この指針自体も、ある種の「宗教性」が感じられるかもしれません。
[[信じるか信じないかはあなた次第]]です。

[126] [[Web]] は、新技術開発が活発に行われ続けている、変化の速い分野です。
設計方針は、時代の変化への追随の足枷になるべきではありません。

[EG[
[127] 例えば、会社の意思決定の速度が遅い場合には、
会社の方針として設計の指針を定めるべきではありません。
]EG]