Web API: The Good Partsを読んだので「設計変更しやすいWeb API」についてまとめた


## はじめに
APIの勉強のために、[Web API: The Good Parts](http://www.amazon.co.jp/Web-API-The-Good-Parts/dp/4873116864)を読みました。平易な日本語で書いてあるので、読みやすかったです。
とはいえ、何度も本を読み返すのは大変なので、自分用まとめも兼ねて書こうと思った次第です。

1個1個まとめていくと結構な量があるので今回は「設計変更しやすいWeb API」についてまとめました。
本でいうと5章に書いてあります。

## この記事も参考に
Web API: The Good Partsの他のまとめ記事もここに載せておきます。

- 2.2: [Web API: The Good Partsを読んだので「良いURI」についてまとめた](http://qiita.com/soyanchu/items/5ca902a7353bb08b7f12)
- 2.6: [Web API: The Good Partsを読んだので「OAuthの仕組み」についてまとめた](http://qiita.com/soyanchu/items/244ab3a35acf4dbf0030)
- 3章: [Web API: The Good Partsを読んだので「レスポンスデータの設計」についてまとめた](http://qiita.com/soyanchu/items/f940a9c86b3122f99c41)
- 4章: [Web API: The Good Partsを読んだので「HTTPの仕様」についてまとめた](http://qiita.com/soyanchu/items/e2989c0f40fd79169bf6)

記事を書く順番は結構バラバラで、今回みたいに3,4章を飛ばして5章を書いたりしています。

## APIは公開し続けていくものだ

Webサービスは静的なウェブサイトと違って、一度公開したらそれで終わりということはなく、ずっと公開していかなければ意味がないですよね。APIもそれは同じです。

APIを追加、変更したり廃止したりすることもあると思います。
今回はこのような起こりうる問題に対応するために、「設計変更しやすいAPI」について見ていきます。

## 設計変更のしやすさの重要性
Web APIはその名の通り、アプリケーションのインターフェイスとしての役割を持ちます。前述のとおりずっと同じというわけにはいかず、追加、変更、廃止など、状況に応じて変化していくものです。修正すると、影響範囲が広くなり、多くの箇所を修正する可能性が出てくるので、あらかじめ設計しておこうという話になります。CSS設計やDB設計をしないで突撃したらカオスなことになるようにAPIも設計が大事ということですね。

さて、

1. 外部に公開しているAPIの場合
2. モバイルアプリケーション向けAPIの場合
3. Webサービス上で使っているAPIの場合

の3つの場合を考えて、変更した場合の影響について考えてみましょう。

### 1. 外部に公開しているAPIの場合

まずはじめに外部に公開しているAPI(LSUDs = Large Set of Unknown Developers)について考えていきます。
具体的にいうと、FacebookやTwitterのAPIなど公開されているエンドポイントを叩くだけで、または簡単な登録を行うだけでだれでも使えるようなものです。
APIの経験が浅い方にも馴染みが深いものかもしれませんね。

さて、APIの変更が突然変更になったらどうでしょうか。
例えば下のような可能性が出てきます。

- エラーが出て処理が止まる
- データに整合性がとれなくなり表示がおかしくなる

APIが改善によって使いやすくなれば、ユーザー側も幸せになれるなら大きな変更でも許容されるかもしれませんが、予告なく変更になったらどうでしょう。
いきなり上のようなバグが出たとユーザーは混乱すると思います。

また変更を周知するのも一苦労です。ドキュメント、Webサイトでアナウンスを出すことはできますが、全員が見ているとは限りません。マイクロな外部に公開しているAPIだと全然見てないで気づいたら、、ってことが起こりそうですね。
それで、利用者が対応しないまま変更したら、「いきなり仕様変更をするとかありえん！」みたいにユーザーは思ってそのAPIを使うのをやめてしまうかもしれません。ユーザー側も仕様変更に合わせて急いで対応を行わないといけませんが、そんないきなり対応をしないといけないAPIは使いたくないからです。

### 2. モバイルアプリケーション向けAPI(SSKDs)の場合

次にモバイルアプリ向けのAPI(SSKDs = Small Set of Known Developers)について考えていきます。
こちらは利用者が公開しているアプリケーションだけなので、修正をしなければならないのは作っている本人だけになるので、外部に公開しているAPIの場合に比べれば影響範囲は小さいといえそうです。

ですが、自由にAPIを更新できるというわけではないです。
モバイルクライアントはユーザーが自分でアップデートしなければ古いままであり、古いクライアントを使い続ける人がいるからです。
AndroidだとOSのバージョンが古くてアップデートできないとか、iOSではマニュアルでアップデートしないとアップデートされないのでバージョンアップしないままの人もいます。
したがって、どのバージョンまでをサポートするかを決める必要がありますが、APIを変えた途端、アプリがエラーを出して使えなくなるという自体は避けなければなりません。

### 3. Webサービス上で使っているAPIの場合

最後にWebサービス上で使っているInternalなAPIについて見ていきます。
これは上2つに比べれば多少状況に楽になります。
クライアント側のコードも自分たちが使っているサーバーから配信しているので、同時に更新することもさほど難しくありません。
が、ブラウザのキャッシュの問題があるので、APIの返すデータとそれを解析して処理するクライアントのコードがあり、どちらかが古いままだとデータが不整合を起こしてしまう可能性があります。

結論、「一度公開をしたWeb APIの仕様を変更するのはいずれにせよ問題が発生する危険性がある」ということになります。
それではどうすればいいのでしょうか。解決策をこれから見ていきたいと思います。

## APIをバージョンで管理しよう
当たり前と言われれば当たり前かもしれませんが、一度公開したAPIをできるかぎり変更しないことが、最善と思われる方法になります。
そうするとサービスの改善が難しくなってしまうのではないか？と思われるかもしれませんが、実際はそんなことはありません。
具体的に言うと、 **新しいAPIを別のエンドポイント、あるいは別のパラメータを付けたURIなど、何らかの新しいアクセス形式で公開** すればいいからです。
つまり、古い形式でアクセスしてきているクライアントに対しては今までと変わらないデータを送り(例えばv1)、新しい形式のアクセスには、新しい形式のデータを返せば良い(例えばv2)のです。
よくAPIでv1, v2というのを見るかもしれませんが、こういった理由からですね。
つまり、 **複数のバージョンのAPIを提供する**というわけです。

複数のAPIを共存させるためには、全く異なるURIでAPIを公開するのが一番わかりやすいでしょう。
ですが、バージョン番号をどうやって指定するかについてはいくつも議論がなされているようです。
ですので、それらの例について3つほど見ていきましょう。

下記の3つの場合を考えていきます。

1. URIにバージョンを埋め込む
2. バージョンをクエリ文字列に入れる
3. メディアタイプでバージョンを指定する

### 1. URIにバージョンを埋め込む

まずはURIにバージョンを埋め込んだ例を見てみます。

```Tumblr
http://api.tumblr.com/v2/blog/good.tumbl.com/info
```

これはTumblrのAPIです。v2というのがバージョン番号ですね。

さてこのバージョン番号の付け方はサービスごとに若干異なっているようなのでまとめておきます。

| サービス       | エンドポイント                                        |
|----------------|-------------------------------------------------------|
| Twitter       | https://api.twitter.com/1.1/statuses/user_timeline.json|
| Facebook       | https://graph.facebook.com/v2.0/me                    |
| LinkedIn       | http://api.linkedin.com/v1/people                     |
| Foursquare     | https://api.foursquare.com/v2/venues/search           |
| ぐるなび       | http://api.gnavi.co.jp/ver1/RestSearchAPI/            |
| ホットペッパー | http://webservice.recruit.co.jp/hotpepper/gourmet/v1/ |
| Dropbox        | https://api.dropbox.com/1/account/info                |
| mixi           | https://api.mixi-platform.com/2/people/@me/@friends   |
| CrunchBase     | http://api.crunchbase.com/v/1/company/facebook.js     |


このように、vを先頭につけたりつけなかったりと色々分かれているようです。筆者の方はvをつけるのが好みであると記載していましたが、"バージョンである"ということがはっきりとわかる、という理由からでした。同様に私もv1のようにバージョンをつけるほうが好みです。

#### バージョン番号をどうつけるか

さて、上の例をもう一度見てみましょう。FacebookやはTwitterはURIにマイナーバージョンを含めているのでこれが一般的だと思うかもしれません。
が、これは少数派(らしい)です。Facebookは、2.0のリリースと同時に一度リリースしたAPIを新バージョンリリース後2年間は動作保証することを発表したため、バージョンを細かく刻むことでメンテナンスがしやすくなる道を選んだのだと考えられる(らしい)です。

FacebookのようなAPIを利用している人だけで膨大になる場合はさておき、普通のサービスではメジャーバージョンにするのがいいのではないかというのが筆者の考えだそうです(私もそこまで細かくバージョンを刻む必要はないと思います)。

なお、マイナーバージョンなどバージョニングのルールは、[セマンティックバージョニング](http://semver.org)についてまとめた[私のQiita - 「セマンティック バージョニング」を読んだのでバージョニングについてまとめた](http://qiita.com/soyanchu/items/72095a7c9fdb7f71b2c3)があるのでそれを参考にしていただければとおもいます。

### 2. バージョンをクエリ文字列に入れる

さて次はバージョンをクエリ文字列に入れる方法について見ていきます。
具体的には以下のような感じです。

```Netfix
http://api-public.netflix.com/catalog/titles/series/70023522?v=1.5
```

さて、先ほど見たパスとクエリ文字列の最大の違いは何でしょうか？
それは、 **省略可能**になるということです。
なので、クエリ文字列の場合は省略した場合のデフォルトのバージョンが決まっているのが普通です。
筆者はパスとクエリ文字列のどちらが好みということかに関しては、パスのほうが好みと書いてありました。
理由は以下の３つとのことです。

- 見た目が冗長であること
- 省略した時デフォルトのバージョンを示すのかが自明でない点
- 常に最新版を同じURIで提供することによって、利用者にトラブルを発生させてしまうリスクがある

私はまだ身近なものについてパスでしかAPIを書いたことも見たこともないので、パスのほうが馴染みがありますね。

### 3. メディアタイプでバージョンを指定する

最後に、メディアタイプでバージョンを指定する方法です。メディアタイプはデータ(文書)のデータ形式を表すものです。例えばJSONだったら application/json みたいになってるものですね。

例えばGithubだとバージョン3のAPIデータのメディアタイプを application/vnd.github.v3+json としているそうです。これによって、Githubのバージョン3のデータ形式であり、JSONを利用していることが一目瞭然です。

この方法は、APIのバージョンというプレゼンテーションレベルの指定がURIに含まれることがなくなり、URIが純粋にリソースを表すものとして使えるなど、HTTPの文法にかなりきちんと則った方法になり、美しい方法だといえますが、Content-Typeが完全にapplication/jsonと一致していないとJSONと判断してくれないクライアントライブラリがあって独自のメディアタイプをエラーと認識してしまう危険性があるなどのデメリットがあります。
ここらへんは読んでおいてなるほどと思いました。


### どの方法がいいのか

どの方法も一長一短ありますが、最もよく利用される方法は1の **URIにバージョンを埋め込む**方法になります。
わかりやすさや普及度からこれが一番使われているようです。

## バージョンを変える際の指針

さて次にバージョンをどのように変えていくかという方針について見ていきます。
APIのバージョニングは、あとから変更しやくするためのものではあります。ですが、それは **変更をいくら変えてもいいという**という意味ではありません。
APIのバージョンを増やすことは、公開側のメンテンスコストも、クライアント側対応のコストも増えてしまうからです。

したがって、後方互換性を保つことが可能な変更は可能な限り同じバージョンのマイナーバージョンアップで対応し、バージョンを上げるのはどうしても **後方互換性を保ったまま修正を行うことが難しい変更を加えなければならない**時にのみ、バージョンを上げるべきです。
軽微な変更(データの名前やデータ形式を変更するなど)の場合はバージョンを上げるべきではありません。

他にもバージョンを上げる指針として **セキュリティや権限などのルールを変更した場合**があります。
例えばベーシック認証をやめてOauthにするといったことです。

あとは **ルールが整理されずに進化されていったAPIをより使いやすく、整理するため**にAPIを整理する場合があるようです。
具体的にはFacebookやTumblrなどがそれにあたるようです。

## APIの提供を終了する場合

バージョンでAPIを分けることによって、新しいバージョンの提供を開始できますが、複数のバージョンを運用し続けるのは運用側にとってもコストになります。
はじめにも述べましたが、APIの古いバージョンをもし終了する場合は、なんのアナウンスもなくいきなり古いバージョンの提供をやめてしまったらユーザーはアクセス出来ない状態になってしまいます。
ですので、終了日をアナウンスする必要があります。
そのために提供終了時の仕様を予め盛り込んでおいたり、利用規約にサポート期限を明記したりするのが解決策としてあるようです。

## おわりに

いかがでしたでしょうか。まだ自分はバージョンを上げるようなAPIを実装した経験はないのですが、もしこれからそういう時が来た時のための方針などが整理できたと思います。
メジャーバージョンアップといわずともマイナーバージョンアップするということはあるかと思いますので、そういう方にとって参考になれば幸いです。
詳しくは[Web API: The Good Parts](http://www.amazon.co.jp/Web-API-The-Good-Parts/dp/4873116864)を読んでいただければと思います。