綺麗なAPIとは開発者にとって理解しやすく、使いやすいAPIです。さらに提供側にとってはメンテナンスしやすく、拡張性も担保されたものになります。そうしたAPIを設計するのは容易ではありませんが、幾つかのルールを設けておくことでも十分に綺麗に設計できるようになるでしょう。
1. モデル型かアクション型か
URLを設計する際にRESTfulに作るのがデファクトになっていますが、その中でもURLの作り方をモデル(ユーザ、商品など)にするか、アクション型(購入する、出席するなど)にするかで分かれます。どちらを採用するにしても明確な基準が必要です。両方を満遍なく取り入れると、非常に分かりづらいものになります。
一般的には GET /users/1 でユーザデータに対する操作であるといった形にします。つまりモデル型です。 となると POST /purchase で購入するというアクションを定義するよりも POST /orders で注文データを作成するといった形の方が自然です。
またログインにおいてもセッションデータを作成するという意味で POST /session のがいいでしょう。セッションはブラウザごとに一つなので複数形ではなく単数形になります。 POST /login といったアクションベースではない方が良いでしょう。
2. RESTfulの原則に従う
RESTfulの原則はURLが操作する対象のリソースを指定し、それに対するCRUD操作をHTTPメソッドで指定するというものです。その原則を尊重することでコントローラの機能を分離し、ソースコードの可読性も高まります。
一つのリソースが複数の状態を持つ場合、例えばタスク管理で考えてみます。
- タスクの一覧(/tasks)
- アクティブなタスクの一覧(tasks/active)
- 期限の近いタスクの一覧(tasks/limit)
- 完了にしたタスクの一覧(tasks/done)
とした場合、これらはすべてGETで処理されるものになります。これをRuby on Railsでハンドリングしようとした場合、ルーティングを設定することで一つのコントローラ(TasksController)で処理することもできます。しかし、管理が煩雑になっていくでしょう。
そこで以下のように分離して考えます。
- タスクの一覧(TasksController#index)
- アクティブなタスクの一覧(Tasks::ActiveController#index)
- 期限の近いタスクの一覧(Tasks::LimitController#index)
- 完了にしたタスクの一覧(Tasks::DoneController#index)
こうすることで一つのコントローラの中に実装されるコード量を減らせるのと同時に、対象になるリソースの限定とHTTPメソッドによる操作というRESTfulの原則が維持されます。それぞれの機能は似たようなもの(ステータスが違う程度)になりますので、実際のコードは共通化されたライブラリを活用することになるでしょう。
3. バージョンをURIに持たせない
APIのバージョンをどこに持たせるかは常に問題になります。URIに入れた場合、多くは /api/1.0/users
のようになります。これは多くの場合、2.0になった時に1.0で動作するライブラリをコピーする必要が出るでしょう。同じようなコードが氾濫することになり、管理が煩雑になります。開発者としても一部は1.0、一部は2.0を使い分ける時に共通したURLが /api/
しかなくなってしまうのは不便です。
そこでHTTPヘッダーやクエリストリングの中にバージョン番号を持たせるのはどうでしょう。よりフレキシブルに変更したいならばクエリストリングになるでしょう。HTTPヘッダーであればURLは共通で使えるようになります。
サーバ側としても既存のシステムがまったく別物に置き換わることはそうそうありませんので、プログラム中でバージョン番号を判定するだけで処理できるようになるでしょう。
4. レスポンスにHALなどを採用する
単なるJSONでは情報が不足するようになっています。そこでJSON APIなどメタデータを追加するJSONフォーマットが望まれるようになっています。その一つ、HALはAWSでも採用されているフォーマットであり、今後デファクトになっていく可能性があります。
HALを使うことでページネーションがある時に次のリンクを示すことができたり、追加のメタデータを付与できます。JSON APIもまた有名なJSONに情報を付与するフォーマットで、必要に応じて採用する方を決定すればいいでしょう。
APIのレスポンスを変えるというのはそうそう簡単ではありませんので、バージョン番号を使ったり、フォーマットを指定した場合などに採用するのがいいでしょう。もちろん、これから作るならばあらかじめ採用を決めておくのが最良です。
5. POST/PUTでもレスポンスボディを返す
APIを使った開発においてよくあるのがPOST/PUTでデータを更新した時に、最新のデータをGETで取り直すというものです。これは2回APIアクセスする必要があってムダです。POSTで作った、PUTで更新したデータについて、その最新の状態をレスポンスに含めるようにしましょう。
特にサーバ側で処理されるデータがある場合、クライアント側ではデータがどういった値を持つかは分かりません。その結果、GETでアクセスする必要が生じてしまいます。ネットワークはボトルネックになりやすいので、クライアントからのアクセスを少なく済むようなサーバ側の実装を心がけましょう。
APIを実装する上でポイントになる部分はもっとたくさんあると思われますが、今回は主なポイントを5つ紹介しました。初期リリース時点では綺麗でも、更新を重ねていく内に破綻していくのはデータベース設計でもよくあることです。データベース管理者が将来的な拡張性も見込んでテーブル設計を行うのと同様に、APIにおいても更新を考えた上でメンテナンス性や論理的破綻を起こさないような設計を行いましょう。