API設計で必要なこと。技術よりも先に、使う人の体験から考える
APIは、SPAやモバイルアプリ、Webアプリケーション、IoTデバイス、デスクトップアプリなどが、データを保存したり読んだりするための窓口です。設計には、テクニックや知識、経験、ベストプラクティス、サーバーコストの話がついて回ります。どれも大事ですが、いちばん先に考えるべきものは別にあります。
CX、つまりカスタマーエクスペリエンス(顧客体験)です。技術ファーストより、顧客ファースト。
この記事は、API設計について参考になった記事を自分なりに整理し、そこから考えたことを社内勉強会で話した内容です。前半は参考記事の整理、後半は自分たちの手順です。
内側からではなく、外側から設計する
APIの設計には、2つの向きがあります。
- インサイドアウト:公開する内部システムやサービスの都合に基づいてAPIを設計する
- アウトサイドイン:作り上げたい顧客体験に基づいてAPIを設計する
利用者がAPIに求めるのは、自分の仕事が簡単になり、生産性が上がることです。その求めに応えるAPIがほかにあれば、利用者はそちらを選びます。だから、まず利用者が何を必要としているかを知り、それに合わせてAPIを作る。これがアウトサイドインです。
この考え方は、Google Cloud のブログ「RESTful Web API 設計のベストプラクティス」で知りました。そこでは設計でつまずきやすい点が6つ挙げられています。読んで自分なりに整理すると、次のようになります。
| つまずきやすい点 | どうするか |
|---|---|
| 内部の都合で設計している | 利用者の話を聞いてユースケースを書き出し、各ケースに必要なデータだけを返すレスポンスの見本を先に作る |
| 利用者にとって複雑すぎる | 中は複雑でも、外から見て簡単に見えるAPIにする。ゼロから作る前提で見直し、信頼できる利用者に試してもらう |
| 呼び出しの回数が多すぎる | 1つの画面に必要なデータを1回で返す「Experience API」を、細かいAPIと併せて用意する。GraphQLも選択肢 |
| 柔軟性に欠けている | 必要な項目だけを返す指定、並び替え、ページネーションをクエリで指定できるようにする |
| 人が読めない | IDをキーにした入れ子や、意味のない「data」のような名前を避ける。最初の読み手は人 |
| RESTのルールに縛られすぎる | 利用者の体験のためにルールを破ることはある。ただし全体で一貫させ、ドキュメントに明記する |
例:オンライン書店のAPIを、外側から設計する
アウトサイドインを自分なりに手順に落とすと、こうなります。オンライン書店のAPIを例にします。
- ユーザーストーリーを書く:書籍を検索したい。書籍の詳細を見たい。書籍をカートに入れたい
- エンドポイントを決める:
GET /books(検索)、GET /books/{id}(詳細)、POST /cart(カートに追加)。リソース指向のURLにする - データの形式を決める:やり取りするJSONの形を、利用者が使いやすい形で決める
- エラーの返し方を決める:
404 Not Foundなら{ "error": "Resource not found" }のように、明確で一貫したメッセージにする - セキュリティを決める:APIキーによる認証、OAuthによる認可など
- 内部を実装する:ここで初めて、データベースから書籍を取り出す処理や、カートに追加する処理を書く
外側のインターフェースを先に固めるので、あとから内部の作りを変えても、利用者には影響しません。長く運用するほど、この順番が効いてきます。
ここから、自分たちはどう考えているか
参考記事は「利用者から考える」という向きを教えてくれますが、実際の案件で最初に何をするかまでは書いていません。そこを自分なりに整理したのが、ここからです。
API設計が必要になる状況は、だいたい次の3つです。
- すでにAPIサーバーが動いていて、そこに新しいAPIを追加する
- すでにAPIサーバーが動いているが、出来がよくない。データ定義を変える、リファクタリングする、ライブラリを更新する、インターフェースを変える
- 新規の案件を受注し、バックエンド開発の責任者になった。まだ何もない
どの場合も、エンドポイントの一覧から書き始めることはしません。順番は次のとおりです。
1. モデルを作る
どんな業務なのか(ドメイン)、誰が使うのか(登場人物)を押さえ、重要なビジネスロジックを中心に大枠のモデルを作ります。
2. 非機能要件を確かめる
どれくらいのデータ量を想定するか。どれくらいの頻度で使われるか。誰が、どこで使うか。求められるセキュリティの水準はどれくらいか。保守は誰がどう行うか。規模感はどうか。ここでの答えが、マイクロサービスにするかどうかの判断につながります。
3. データベースを選ぶ
RDBかNoSQLか、リレーションはどうか、マイクロサービスかモノリシックか、を決めます。判断の軸は次のとおりです。
| 観点 | RDB | NoSQL |
|---|---|---|
| データモデル | 表形式で、スキーマを厳密に定義。関連とトランザクションが必要な場合に向く | 柔軟なスキーマ。構造が変わりやすい場合に向く |
| データの複雑さ | 複雑な関係や結合、ACIDトランザクションに向く | 単純な構造や、分散して高いスケーラビリティが必要な場合に向く |
| スケーラビリティ | 垂直が主流。水平は可能だが複雑になりがち | 水平スケーリングが容易 |
| クエリ | 複雑なSQLや結合に強い | 単純な検索やフィルタに向く |
| 一貫性と可用性 | ACIDで一貫性を保つ。可用性に影響することがある | BASEモデルで可用性が高い。一貫性は柔軟 |
もう一つ、構成上の判断があります。AWS Lambda からRDBへ接続する場合、コネクションプーリングがまだ十分に信用できません。RDBを選ぶなら、Spring、PHP、Pythonなどのモノリシックな構成も視野に入れて考えます。
4. ER図を描く
RDBかNoSQLかで、ここからの進め方が変わります。作ったモデルをどういうテーブル定義にするか、プライマリキーは何かを決めます。
5. APIのインターフェースを決める
RESTにするか、ユースケースごとのAPIにするか。アプリにとって使いやすいのはどちらかで決めます。1つの画面にはコンポーネントごとに必要なデータがあり、それをまとめて取るか、分けて取るか。画面を全部取得してから描画するのか。こうした画面側の視点で、エンドポイントの切り方を決めます。
まとめ
参考記事を整理して分かったのは、API設計で最初に決めるのはエンドポイントの名前ではなく、誰が、どんな体験のために使うのか、ということでした。そこに自分たちの手順を重ねると、モデル、非機能要件、データベース、ER図、インターフェースの順になります。この順で進めると、内部の都合に引きずられた設計になりにくい、というのが今の考えです。
参考:Google Cloud ブログ「RESTful Web API 設計のベストプラクティス」、Google Cloud Community「Designing APIs from the Outside-In」