HerokuのAPIデザイン
Herokuが自ら実践しているAPIデザインガイドをGithubに公開した.
このガイドは些細なデザイン上の議論を避けて,ビジネスロジックに集中すること目的としている.Heroku特有なものではなく,一般にも十分適用できる知見となっている.
最近は,モバイル向けにAPIをつくることも多いため,勉強もかねて抄訳した.なお内容は,HTTP+JSONのAPIについて基本的な知識があることが前提となっている.
適切なステータスコードを返す
それぞれのレスポンスは適切なHTTPステータスコード返すこと.例えば,”成功”を示すステータスコードは以下に従う.
200
:GET
やDELETE
,PATCH
リクエストが成功し,同時に処理が完了した場合201
:POST
リクエストが成功し,同時に処理が完了した場合202
:POST
やDELETE
,PATCH
リクエストが成功し,非同期で処理が完了する場合206
:GET
のリクエストは成功したが,レスポンスがリソースに対して部分的である場合
その他のクライアントエラーやサーバエラーに関しては,RFC 2616を参照(日本語だと,このサイトや“Webを支える技術”が詳しい).
可能な全てのリソースを提供する
そのレスポンスで可能な全てのリソース表現(つまり,全ての要素とそのオブジェクト)を提供すること.ステータスコードが200
もしくは201
のときは常に全てのリソースを提供する.これはPUT
やPATCH
,DELETE
リクエストでも同様.例えば,
1 2 |
|
1 2 3 4 5 6 7 8 9 |
|
ステータスコードが202
の場合は,完全なリソース表現は含めない.例えば,
1 2 |
|
1 2 3 4 |
|
リクエストボディ中のシリアル化されたJSONを受け入れる
フォームデータに加えて,もしくは代わりに,PUT
やPATCH
,POST
のリクエストボディ中のシリアル化されたJSONを受け入れること.これにより,リクエストとレスポンスが対称になる.例えば,
1 2 3 |
|
1 2 3 4 5 6 7 8 9 |
|
リソースの(UU)IDを提供する
それぞれのリソースにデフォルトでid要素を提供すること.特別な理由がない限りUUIDを使うこと.サービスの他のリソースの中で一意でないidを使わないこと.
小文字かつ8-4-4-4-12
フォーマットを使うこと.例えば,
1
|
|
タイムスタンプを提供する
デフォルトでリソースのcreated_at
とupdated_at
のタイムスタンプを提供すること.例えば,
1 2 3 4 5 6 |
|
これらのタイムスタンプは,削除されうるリソースには必要ないかもしれない.
時刻はISO8601フォーマットのUTCを使う
時刻はUTC(協定世界時)のみを返答する,もしくは受け入れること.ISO 8601フォーマットを用いること.例えば,
1
|
|
一貫したパス名を使う
リソース名:リソース名には複数形を使う.ただし,要求されるリソースがシステム全体でシングルトンである場合は,単数形を使う(例えば,ほとんどのシステムではユーザはただ1つのアカウントのみを持つ).これにより,リソースへの参照方法に一貫性を持たせることができる.
アクション名:パスの末尾にリソースに対する特別なアクションを必要としないのが望ましい.必要な場合は,それを明確にするため,以下のようにアクション名をactions
の後に続けて記述できるようにする.
1
|
|
例えば,
1
|
|
パス名と要素名には小文字を使う
ホスト名に合わせて,パス名には小文字,区切り文字には-
を使うこと.例えば,
1 2 |
|
同様に要素名にも小文字を使うこと.Javascriptで使うことを考慮して,区切り文字には_
を使うこと.例えば,
1
|
|
外部キーの参照はネストする
外部キーによる一連の参照はネストして記述する.例えば,
1 2 3 4 5 |
|
とするのではなく,以下のようにする.
1 2 3 4 5 6 7 |
|
これにより,レスポンスの構造を変更したり,トップレベルのフィールドを追加することなく,関連した情報を含めることができる.例えば,
1 2 3 4 5 6 7 8 9 |
|
id以外の参照方法をサポートする
ユーザにとってリソースの特定にidを使うのが不便な場合がある.例えば,ユーザはHerokuアプリケーションをUUIDではなく,名前で見分けているかもしれない.このような場合を考慮して,idと名前の両方でリソースにアクセスできるとよい.例えば,
1 2 3 |
|
ただし,名前のみでしかアクセスできないといったことは避ける.
構造的なエラーを生成する
エラーの際は,一貫した構造的なレスポンスを生成すること.レスポンスには,コンピュータが解釈しやすいエラーid
と,ユーザが理解しやすいエラーmessage
を含めること.さらに,エラーとその解決方法を示すさらなる情報へのurl
も含めるとよい.例えば,
1
|
|
1 2 3 4 5 |
|
エラーのフォーマットと,id
のドキュメントを作成すること.
Etagによるキャッシュをサポートする
返答するリソースのバージョンを示す,ETag
ヘッダを含めること.クライアントはIf-None-Match
ヘッダで,キャッシュが最新であるかをチェックできるようにするべき.
Request-Idでリクエストを追跡する
UUIDによるRequest-Id
ヘッダをそれぞれのAPIのレスポンスに含めること.サーバとクライアント両方でその値のログをとれば,リクエストのデバッグの際に有用になる.
Content-Rangeでレスポンスを分割する
データ量が大きくなりそうな場合は,レスポンスを分割すること.Content-Range
ヘッダを使って,コンテンツの範囲を指定できるようにする.リクエストとレスポンスのヘッダ,ステータスコードなどは“Heroku Platform API on Ranges”の例に従うこと.
制限の状態を示す
クライアントからのリクエストを制限することで,サービスが不安定になることを防ぐこと.リクエストの制限にはトークンバケットアルゴリズムが使える.
RateLimit-Remaining
ヘッダを使って,リクエストトークンの残量を返答すること.
Acceptsヘッダーでバージョニングする
始めからAPIをバージョニングすること.Accepts
ヘッダーを使ってバージョンを指定する.例えば,
1
|
|
デフォルトのバージョンを持たないほうがよい.クライアントに対して特定のバージョンを指定することを明示的に指示する.
パスのネストを最小限にする
ネストした親子関係をもつリソースのデータモデルでは,パスは深くネストすることになる.例えば,
1
|
|
ルートパスにリソースを配置するようにパスのネストの深さを制限すること.ネストをある特定の範囲の集合を示すために使うこと.例えば,上の例では,1つのdynoは1つのappに属し,1つのappは1つのorgに属する,
1 2 3 4 5 |
|
コンピュータが理解しやすいJSONスキーマを提供する
コンピュータが理解しやすいJSONスキーマを提供すること.prmdを使ってスキーマを管理し,prmd varify
でそれを評価すること.
ユーザが理解しやすいドキュメントを準備する
クライアントの開発者がAPIを理解できるように読みやすいドキュメントを準備すること.
prmdを使ってスキーマを作成したなら,prmd doc
で簡単にmarkdown形式のドキュメントを生成できる.
これに加えて,以下のようなドキュメントを準備すること.
- 認証方法.認証トークンの取得方法
- APIの安定性とバージョン.望ましいバージョンの選択方法
- 共通のリクエスト/レスポンスヘッダ
- エラーのフォーマット
- 様々な言語によるAPIの利用例
実行可能な実例を提供する
ユーザがターミナルからAPIの動作を確認できるように,実行可能な実例を提供すること.APIを試すための手順をできる限り最小限にする.例えば,
1 2 |
|
prmdmarkdownのドキュメントを生成していれば,例も同時に得られる.
安定性を説明する
APIの安定性を説明すること.例えば,プロトタイプか,開発中か,プロダクションレベルかを示す.
プロダクションで利用可能である,もしくは安定であることを宣言したら,そのバージョンで後方互換を崩すような変更を加えないこと.後方互換を崩す場合は,バーションを上げること.
詳細はHeroku API compatibility policyを参考に.
SSLを必須にする
APIへのアクセスはSSLを必須にすること.いつSSLを使い,いつ使わないかではなく,だた常にSSLを必須にする.
デフォルトでJSONを整形する
ユーザが初めてAPIを使うときは,おそらくコマンドラインからcurl
を使う.コマンドライン上でレスポンスが整形されていれば,ユーザはAPIをより理解しやすくなる.例えば,
1
|
|
ではなく,以下のようにレスポンスを出力する.
1 2 3 4 5 6 7 8 |
|