## 返回适当的状态码
为每个请求返回适当的状态码,成功的请求应该遵守如下规则:
* 200: 当GET请求成功完成,DELETE或者PATCH请求同步完成。
* 201: 同步方式成功完成POST请求。
* 202: POST,DELETE或者PATCH请求提交成功,稍后将异步的进行处理。
* 206: GET请求成功完成,但只返回了部分数据。参见用[ranges分页](https://github.com/easychen/http-api-design/tree/cn#paginate-with-ranges)
注意认证和认证错误的使用:
* 401 Unauthorized: 请求失败,因为用户没有进行认证。
* 403 Forbidden: 请求失败,因为用户被认定没有访问特定资源的权限。
返回合适的状态码可以为错误提供更多的信息:
* 422 Unprocessable Entity: 你的请求服务器可以理解,但是其中包含了不合法的参数。
* 429 Too Many Requests: 请求频率超配,稍后再试。
* 500 Internal Server Error: 服务器出错了,检查网站的状态,或者报告问题。
根据[HTTP response code ](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)规范的指导来设计用户错误和服务器错误情况下的状态码。
## 总是返回完整的资源
对于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
...
{}
~~~
## 在请求body中接收JSON序列
不要将额外信息放到form-encoded里边,而是将其JSON序列放到PUT,PATCH或POST请求的Body中。这样才能和同为JSON序列的响应Body对称(作者你是处女座么),如:
~~~
$ 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"
},
...
}
~~~
## 使用一致的路径格式
**资源名称**
使用复数来命名资源,除非该资源在系统中是单件(比如,在绝大多数系统中,一个用户只能拥有一个账户)。这样在你引用特定资源时可以保持一致性。
**动作**
对独有的资源使用不需要特定动作的endpoint格式。这样当需要特定的动作,只需要把它们放到标准的actions前缀后边,就可以清晰的描述它们:
~~~
/resources/:resource/actions/:action
~~~
如:
~~~
/runs/{run_id}/actions/stop
~~~
## 小写所有路径和属性
使用小写字母和减号命名路径,这样Hostname可以对齐(作者你真的是处女座):
~~~
service-api.com/users
service-api.com/app-setups
~~~
同样小写属性,但使用下划线来分割,这样属性名在JavaScript中可以不用加引号:
~~~
service_class: "first"
~~~
## 支持非ID的参数作为快捷方式
有时候要求最终用户提供ID来表示资源会比较麻烦,比如,用户可能只想得起Heroku的Appname,而应用本身却是由UUID来区分的。在这种情况下,我们可以同时接收ID和Name:
~~~
$ 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属于一个app,而app又属于一个org的例子:
~~~
/orgs/{org_id}
/orgs/{org_id}/apps
/apps/{app_id}
/apps/{app_id}/dynos
/dynos/{dyno_id}
~~~