概要
Atlassian SourceTree はWinows用の無料のGitとMercurialクライアントです。
Atlassian SourceTree はMac用の無料のGitとMercurialクライアントです。
HTTP API デザインガイド
イントロダクション
このガイドでは、Heroku Platform API での仕事から導きだされた、 HTTP+JSON API の設計手法について記述しています。
このガイドでは、上記の API への追加事項をお伝えし、Heroku での新しい 内部 API の設計手法についても説明します。それらは Heroku 以外の API 設計者にも興味深いものだと思います。
私たちのこのガイドでの目標は、デザイン上の時間とエネルギーの浪費を 避け、一貫性を保ち、ビジネスロジックの部分に注力することです。 私たちは API の設計について、必ずしも 唯一の/理想的な方法 を探して いる訳ではなく、よい、一貫性のある、明快な方法を探しています。
このガイドを読むにあたっては HTTP+JSON API の基本をよく理解されて いると仮定しています。このガイドの中では HTTP+JSON API についての 基本的な説明は網羅されていません。
このガイドについてのご意見をお待ちしています。
この日本語訳への注記
(この章だけは日本語訳に固有のものです。) この文書は HTTP API Design Guide の日本語訳です。 この日本語訳の文書のライセンスはオリジナルの文書に準じます。 詳細は ライセンス のファイルをご覧ください。 翻訳の間違いや誤字、つっこみなどありましたら、ぜひ issue, pull request いただけるとうれしいです。
コンテンツ
共通
TLS の必須化
例外なく、API へのアクセスには TLS の利用を必須とすること。 TLS を利用する、しないについて検討したり説明することに意味はありません。 常に TLS の利用を必須とすべきです。
Accept header でのバージョン情報の通知
最初から API にバージョン情報を用意しておくこと。例えば固有の
Content-Type などと共にバージョン情報を通知するために、Accept
header を使いましょう。
Accept: application/vnd.heroku+json; version=3
API がデフォルトのバージョンを持つことは推奨しません。その代わり、 特定のバージョンの API でしか使用できないことを、明確にクライアントに 要求する様にしましょう。
Etags によるキャッシングのサポート
返却されるリソースの特定のバージョンを識別するため、全てのレスポンスに
ETag header を含めること。API の利用者が If-None-Match header で
値を指定することにより、その後のリクエストが期限切れかどうかをチェック
できる様にするべきです。
Request-Id によるリクエストのトレース
UUID 値を取り込むために、個々の API レスポンスに Request-Id header を
含めること。サーバとクライアントのログの双方にこの値を含めることで、
リクエストのトラッキングとデバッグの助けになるでしょう。
範囲指定によるページネーション
大量のデータを生成しやすいレスポンスではページネーションすること。
ページネーションのリクエストを伝える為には、Content-Range header を
使いましょう。リクエストとレスポンスの header、ステータスコード、
制限値、発行要求、ページ遷移の詳細については、
Heroku Platform API on Ranges の例を参考にしてください。
リクエスト
適切なステータスコードの返却
レスポンスごとに適切な HTTP ステータスコードを返却すること。 成功したレスポンスでは以下に沿ったコードにすべきです。
200:GETの呼び出しと、DELETEやPATCHの同期呼び出しが成功しました。201:POSTの同期呼び出しが成功しました。202:POST,DELETE,PATCHの非同期呼び出しが成功しました。206:GETの呼び出しに成功しましたが、一部の応答のみが返ってきました。
above on ranges を参照してください。
「認証」と「認可」のエラーコードの違いに注意しましょう。:
401 Unauthorized: ユーザーが認証されていない為に失敗しました。403 Forbidden: ユーザーが特定のリソースにアクセスするための
「認可」を得られないために失敗しました。
エラーとなった際の追加情報を提供できる適切なコードを返却しましょう。:
422 Unprocessable Entity: 無効なパラメーターが含まれているため、
リクエストを正しく解釈できませんでした。429 Too Many Requests: リクエストが制限されているため、しばらくして
再送してください。500 Internal Server Error: サーバー上で何らかの問題が発生しているため、
サイトの状態を確認して/または問題を管理者まで報告してください。
ユーザーエラー、サーバーエラーに対するステータスコードの手引きについては、 HTTP response code specを参照してください。
利用可能な全てのリソース情報の返却
レスポンス中に、都度可能な限り、全てのリソース表現
(即ち全ての属性を持ったオブジェクト)を含めること。
ステータスコードが 200, 201 の結果を返却する場合は、
PUT/PATCH/DELETE のリクエストに対する結果を含めて、
常に全てのリソース情報を返却しましょう。
例えば..:
$ curl -X DELETE \ https://service.com/apps/1f9b/domains/0fd4 HTTP/1.1 200 OK Content-Type: application/json;charset=utf-8 ... { "created_at": "2012-01-01T12:00:00Z", "hostname": "subdomain.example.com", "id": "01234567-89ab-cdef-0123-456789abcdef", "updated_at": "2012-01-01T12:00:00Z" }
ステータスコード 202 の場合は、全てのリソース表現は含められないでしょう。
例えば..:
$ curl -X DELETE \ https://service.com/apps/1f9b/dynos/05bd HTTP/1.1 202 Accepted Content-Type: application/json;charset=utf-8 ... {}
request body で 直列化(シリアライズ)された JSON を受け付ける
PUT/PATCH/POST では request body で直列化(シリアライズ)
された JSON を受け付けること。代わりに、またはそれに加えて
form-encode されたデータがあってもかまいません。この要件は、
直列化(シリアライズ)された JSON レスポンスとの間に対称性を
作り出します。
例えば..:
$ curl -X POST https://service.com/apps \ -H "Content-Type: application/json" \ -d '{"name": "demoapp"}' { "id": "01234567-89ab-cdef-0123-456789abcdef", "name": "demoapp", "owner": { "email": "username@example.com", "id": "01234567-89ab-cdef-0123-456789abcdef" }, ... }
一貫性のあるパス・フォーマットを使う
リソース名
問い合わせのあるリソースは、システム内で一つしかない状態でなければ、 複数形のリソース名を使うこと。(例えば、ほとんどのシステムでは、 指定されたあるユーザーは、常に一つのアカウントのみを持っています。) これにより、特定のリソースを参照する方法として一貫性を保つことができます。
アクション名
個々のリソースのために特別なアクションを必要としないエンドポイントの
レイアウトを選択すること。特別なアクションが必要なケースでは、明確に
示すために標準的な actions という接頭辞の下に配置しましょう。
/resources/:resource/actions/:action
例えば..:
/runs/{run_id}/actions/stop
パスと属性の小文字化
ホスト名とあわせるため、小文字化し "/" で区切られたパス名を使うこと。
例えば..:
service-api.com/users service-api.com/app-setups
また、属性についても小文字化しましょう。そして単語の区切り文字には "_" を使いましょう。それにより、属性名を JavaScript で引用符なしに タイプできます。
例えば..:
service_class: "first"
利便性のための ID なしの間接参照(デリファレンス)のサポート
場合によっては、あるリソースを識別するための ID を提供することが、 エンドユーザーに不便を強いることがあるかもしれません。 例えば、ユーザーは、Heroku のアプリ名を条件として考慮できますが、 そのアプリは UUID でも識別できます。このケースでは、ID か名前の どちらかでリクエストを受け付けたいでしょう。
例えば..:
$ curl https://service.com/apps/{app_id_or_name} $ curl https://service.com/apps/97addcf0-c182 $ curl https://service.com/apps/www-prod
ただし ID を除外して名前のみを受け付けてはいけません。
パスの入れ子の最小化
リソースの関係性が親子の入れ子になっているデータモデルでは、 パスが深い入れ子になることがあります。
例えば..:
/orgs/{org_id}/apps/{app_id}/dynos/{dyno_id}
ルート・パスでリソースを検索する様にすることで、入れ子の深さを 制限しましょう。スコープ内のコレクションを提示するために入れ子 を使いましょう。例えば、上記のケースでは、dyno は組織に属する アプリに属しています。
/orgs/{org_id} /orgs/{org_id}/apps /apps/{app_id} /apps/{app_id}/dynos /dynos/{dyno_id}
レスポンス
リソース情報での (UU)ID の提供
デフォルトで各リソースに id 属性を付与すること。
特別に大きな理由がない限り、UUID を使いましょう。
サービスのインスタンス間や、サービス内の異なるリソース情報間で グローバルに一意でない ID、特に自動インクリメントされた ID を 使用しないでください。
例えば 8-4-4-4-12 を小文字化した UUID のフォーマットは、
以下の通りとなります。
"id": "01234567-89ab-cdef-0123-456789abcdef"
標準のタイムスタンプの提供
リソース情報のタイムスタンプとして、デフォルトで、create_at と
update_at を提供すること。
例えば..:
{ ... "created_at": "2012-01-01T12:00:00Z", "updated_at": "2012-01-01T13:00:00Z", ... }
これらの項目は幾つかのリソース情報では直感的ではないかもしれませんが、 その場合は省略してもよいです。
時刻には ISO8601 形式の UTC を使う
時刻は UTC のみを受け付け、返却すること。 時刻表現には ISO8601 形式を用いること。
例えば..:
"finished_at": "2012-01-01T12:00:00Z"
入れ子の場合の外部キーの扱い
入れ子になったオブジェクトへの外部参照キーは直列化(シリアライズ)すること。
以下の代わりに..:
{ "name": "service-production", "owner_id": "5d8201b0...", ... }
以下の様にしましょう:
{ "name": "service-production", "owner": { "id": "5d8201b0..." }, ... }
このアプローチにより、レスポンスの構造を変更することなく、また、 トップレベルのレスポンス・フィールドを追加することなく、関連する リソースに関する情報を自由に追加できます。
例えば..:
{ "name": "service-production", "owner": { "id": "5d8201b0...", "name": "Alice", "email": "alice@heroku.com" }, ... }
構造化されたエラーの生成
エラー時には一貫性のある、構造化された response body を生成すること。
ここには、プログラムに読み取りやすいエラー id と、人間に読み取りやすい
エラー message、さらにオプションとして、エラーと解決方法についての追加
情報をクライアントに提示する url を含みます。
HTTP/1.1 429 Too Many Requests
{ "id": "rate_limit", "message": "Account reached its API rate limit.", "url": "https://docs.service.com/rate-limits" }
エラーフォーマットと、クライアントが遭遇する可能性のある エラー id は
文書化しましょう。
リクエスト上限の提示
サービスの健全性を担保し、他のクライアントに対する高度なサービス品質を 維持するために、クライアントからのリクエスト上限を設定すること。 リクエスト上限を定量化するためには、token bucket algorithm を利用できます。
RateLimit-Remaining response header で、個々のリクエストに対する
リクエスト・トークンの残りの数を返却しましょう。
JSON はデフォルトでは pretty 表示に
ユーザーが最初に API を目にするタイミングでは、コマンドライン上で curl を使う 可能性が高いです。 pretty 表示であれば、コマンドライン上で API レスポンスを理解することが、遥かに 簡単です。 開発者の利便性のため、JSON のレスポンスは pretty 表示にしましょう。
例えば、以下の代わりに:
{"beta":false,"email":"alice@heroku.com","id":"01234567-89ab-cdef-0123-456789abcdef","last_login":"2012-01-01T12:00:00Z", "created_at":"2012-01-01T12:00:00Z","updated_at":"2012-01-01T12:00:00Z"}
以下を使いましょう:
{ "beta": false, "email": "alice@heroku.com", "id": "01234567-89ab-cdef-0123-456789abcdef", "last_login": "2012-01-01T12:00:00Z", "created_at": "2012-01-01T12:00:00Z", "updated_at": "2012-01-01T12:00:00Z" }
ユーザーのターミナル・プロンプトを阻害しないために、レスポンスには末尾に 改行を含める様にしてください。
ほとんどの API にとって、全てのタイミングで pretty 表示のレスポンスを返す ことについて、性能面への影響はないでしょう。 パフォーマンスに気を使う一部の API(例えば極度に高トラフィックなもの)や、 特定のクライアント(例えばヘッドレスなプログラムで使われることが知られて いるもの)では pretty 表示を行わない様にすることもできます。
その他
プログラム向けの JSON schema の提供
正確に API を実行するのに必要な、プログラム向けの schema を提供すること。
schema を管理するためには prmd を使いましょう。
prmd verify で正しいことを検証できます。
人間に読みやすいドキュメントの提供
クライアントの開発者が API を理解するのに役立つ、人間に読みやすい ドキュメントを提供すること。
前述の prmd を使って schema を作成する場合、prmd doc で簡単に
全てのエンドポイントに対する Markdown 形式のドキュメントを生成
できます。
エンドポイントの詳細を追加するにあたって、以下の情報を API の 概要として提供できます。
- 認証について。ここには認証トークンの取得と使い方を含みます。
- API の安定性とバージョン管理方法について。ここには希望する
API バージョンを指定する方法を含みます。 - 共通のリクエストおよびレスポンスヘッダーについて。
- 直列化(シリアライズ)されたエラーのフォーマットについて。
- 別言語のクライアントによる API の使い方の例。
実行可能なサンプル例の提供
API の呼び出しが動作するところを直接ターミナルから入力できる、 実行可能なサンプル例を提供すること。 可能な限りこれらのサンプル例は逐語的に使えて、API を試すのに 最小限の作業ですむ様にするべきです。
例えば..:
$ export TOKEN=... # ダッシュボードから取得 $ curl -is https://$TOKEN@service.com/users
prmd を使って Markdown 形式のドキュメントを生成していれば、 自由に個々のエンドポイントに対するサンプル例を取得できます。
安定性の説明
API や様々なエンドポイントの安定性について、その成熟度と安定性に 応じて、prototype/development/production の様なフラグで説明すること。
安定性と変更管理に対するアプローチについては Heroku API compatibility policy を 参考にしてください。
API が production-ready となり、stable になったと宣言された後では、 その API バージョンの中では、後方互換性のない変更は加えない様に しましょう。後方互換性のある変更を加えたい場合は、バージョン番号を 増やして新しい API を作成しましょう。