## 響應(Responses)
### 返回合適的狀態碼
為每一次的響應返回合適的HTTP狀態碼。 好的響應應該使用如下的狀態碼:
* `200`:?`GET`請求成功,及`DELETE`或`PATCH`同步請求完成,或者`PUT`同步更新一個已存在的資源
* `201`:?`POST`?同步請求完成,或者`PUT`同步創建一個新的資源
* `202`:?`POST`,`PUT`,`DELETE`,或`PATCH`請求接收,將被異步處理
* `206`:?`GET`?請求成功,但是只返回一部分,參考:[上文中范圍分頁](https://github.com/ZhangBohan/http-api-design-ZH_CN#%E6%8C%89%E8%8C%83%E5%9B%B4%E5%88%86%E9%A1%B5)
使用身份認證(authentication)和授權(authorization)錯誤碼時需要注意:
* `401 Unauthorized`: 用戶未認證,請求失敗
* `403 Forbidden`: 用戶無權限訪問該資源,請求失敗
當用戶請求錯誤時,提供合適的狀態碼可以提供額外的信息:
* `422 Unprocessable Entity`: 請求被服務器正確解析,但是包含無效字段
* `429 Too Many Requests`: 因為訪問頻繁,你已經被限制訪問,稍后重試
* `500 Internal Server Error`: 服務器錯誤,確認狀態并報告問題
對于用戶錯誤和服務器錯誤情況狀態碼,參考:?[HTTP response code spec](https://tools.ietf.org/html/rfc7231#section-6)
### 提供全部可用的資源
提供全部可顯現的資源 (例如: 這個對象的所有屬性) ,當響應碼為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
...
{}
~~~
### 提供資源的(UU)ID
在默認情況給每一個資源一個`id`屬性。除非有更好的理由,否則請使用UUID。不要使用那種在服務器上或是資源中不是全局唯一的標識,尤其是自動增長的id。
生成小寫的UUID格式?`8-4-4-4-12`,例如:
~~~
"id": "01234567-89ab-cdef-0123-456789abcdef"
~~~
### 提供標準的時間戳
為資源提供默認的創建時間?`created_at`?和更新時間?`updated_at`,例如:
~~~
{
...
"created_at": "2012-01-01T12:00:00Z",
"updated_at": "2012-01-01T13:00:00Z",
...
}
~~~
有些資源不需要使用時間戳那么就忽略這兩個字段。
### 使用UTC(世界標準時間)時間,用ISO8601進行格式化
在接收和返回時都只使用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"
},
...
}
~~~
### 生成結構化的錯誤
響應錯誤的時,生成統一的、結構化的錯誤信息。包含一個機器可讀的錯誤?`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](http://en.wikipedia.org/wiki/Token_bucket)技術量化請求限制。
為每一個帶有`RateLimit-Remaining`響應頭的請求,返回預留的請求tokens。
### 保證響應JSON最小化
請求中多余的空格會增加響應大小,而且現在很多的HTTP客戶端都會自己輸出可讀格式("prettify")的JSON。所以最好保證響應JSON最小化,例如:
~~~
{"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"
}
~~~
你可以提供可選的方式為客戶端提供更詳細可讀的響應,使用查詢參數(例如:`?pretty=true`)或者通過`Accept`頭信息參數(例如:`Accept: application/vnd.heroku+json; version=3; indent=4;`)。