API開発に携わる方におすすめの書籍「The Web API Good Parts」をベースに、
押さえておきたい基本的な部分をまとめました。
APIを開発している方だけではなく、APIを呼び出しているフロントエンドの方にもおすすめの1冊です。
2014年発行なので例が古かったりしますが、基本的な考えを学ぶにはベストな1冊だと個人的には思ってます!
アプリケーションの概要を把握する
API設計を行う前に、APIを利用するクライアントアプリケーションについて理解を深めましょう。
- 画面設計と遷移方法を整理して、APIがどんな機能を提供しなければならないか整理する
- まず箇条書きで整理してみましょう。
※もしかすると1つにまとめられるAPIがあるかもしれませんが、この時点では機能整理が目的なのでまとめようとしないでOKです。
- まず箇条書きで整理してみましょう。
必要なデータを整理する
画面は異なっていても、必要なデータがほぼ同じというケースがあると思います。
また、機能ごとに整理しただけでは画面ごとに大量のAPIを実行する必要が発生するケースも出てくるかもしれません。
API実行回数が多いとその分ネットワークトラフィックのレイテンシーの影響を受けやすくなってしまうため、なるべく1つの画面で実行されるAPIは少ない方が好ましいです。
1でアプリケーションの概要を把握したら、必要なデータからAPIをまとめていけないか検討していきましょう。
エンドポイントを設計する
- エンドポイント設計のコツ
- エンドポイントは覚えやすく、どんな機能を持つのかURIからわかること
- 小文字のみを利用する
- リソースに複数形を利用する
- 単語を繋げる必要がある場合はハイフンを利用する
- ホスト名を考える
- 主流はapi.example.com
- レスポンスの内部構造を考える
-
なるべくAPIのアクセス回数が少なくなるように、APIのユースケースをきちんと考える
- APIがバックエンドのテーブル構造を反映する必要はない。
- APIはアプリケーションのインターフェースであり、DBへのアクセスインターフェースではない
-
レスポンスの内容をユーザが選べるようにする
- クエリパラメータで指定
- レスポンスグループを設計する(small/medium/large)
- AmazonのProduct Advertising APIがこの思想
-
なるべくフラットになるように設計する
- どうしても階層構造の方がわかりやすい場合のみ、階層構造をもつ
NG { "id":123, "name":"taro", "profile":{ "gender":"male", "birthday":19901124 }
OK { "id":123, "name":"taro", "gender":"male", "birthday":19901124 }
-
配列レスポンスはオブジェクトで包む
{ "users":{ "id":123, "name":"taro", "gender":"male", "birthday":19901124 } }
-
バージョン管理を考える
- APIバージョン管理
-
バージョンの考え方を知る
- 1.2.3(メジャー、マイナー、パッチ)
- メジャー:後方互換性のない更新
- マイナー:後方互換性のある機能変更
- パッチ:APIに変更がないバグ修正など
- 1.2.3(メジャー、マイナー、パッチ)
-
メジャーバージョンだけをURIに含める
- 後方互換性を失ってもいいと判断できるほど大きな変更の場合のみバージョンを上げる
-
更新のコツ
- 例えば性別(gender)を数値から文字列に変更したい場合
- genderは残しておいて、genderStrをレスポンスに追加する
- ドキュメントに、genderは廃止予定とマークしておく
- 例えば性別(gender)を数値から文字列に変更したい場合
-
その他のコツ
- 大量データの一部を取得するさいに、取得数と取得位置のクエリパラメータで指定する
- 絶対位置で取得する(「このIDより前のもの」「この時刻より古いもの」など)
- 絞り込みパラメータ
- 絞り込みフィールドを指定する =>users?name=ken
- 全文検索で部分一致 => users?q=ken
- クエリパラメータとパスの使い分け
- パス:一意なリソースを表すのに必要な情報
- クエリパラメータ:省略可能かどうか (絞り込みのクエリパラメータは省略すると全取得)
- 配列のレスポンス
- オブジェクトで包む
- 続きがある場合は続きがあることと、そのURIやパラメータをレスポンスする
- hasNext, nextPageParam, nextPageToken, nextPageUriなど
- 巨大なIDは、文字列にした値も一緒にレスポンスする
- id,id_str
- PUT,PATCHの場合は200とともにそうしたデータを返す
- POSTの場合は201
- DELTEは204
- データが存在しないのは200で空データをレスポンス(この書籍と違うところ)
APIエンドポイント例
(http://api.example.com/v1/)
[基本設計]
ユーザ一覧取得 users GET
ユーザの新規登録 users POST
特定ユーザ情報の取得 users/:id GET
ユーザ情報の更新 users/:id PUT/PATCH
ユーザ情報の削除 users/:id DELETE
「友達関連のAPI」
・友人の友達一覧取得
GET users/:id/friends
・友人の追加
POST users/:id/friends
・友人の削除
DELETE users/:id/friends/:id (自身のID、友人のID)
「近況に関するエンドポイント」
近況の編集 updates/:id PUT
近況の削除 updates/:id DELETE
近況の投稿 updates/ POST
特定ユーザの近況の取得 users/:id/updates GET
友達の近況一覧の取得 users/:id/friends/pudates GET
検証
-
APIのロジックに進む前に、リクエストペイロードのチェックを行う
-
不正なペイロードが含まれるリクエストは無効にすること
optionalなプロパティがある場合にクライアントがタイプミスをしている場合、
クライアントが想定しない挙動になる恐れがある -
レスポンス前に、レスポンスペイロードのチェックを行う
- 必須のプロパティが存在しない場合はエラー
- 定義していないプロパティが含まれる場合はレスポンスしない
- (APIの内容によっては、上記実装が必ずしも正しいとは限りません。)