因此,大多数 API 只会使用一个小小的子集,比如 Google GData API 用到 10 个状态码,Netflix 用到 9 个,Digg 只用到 8 个。
Google Gdata
200 201 304 400 401 403 404 409 410 500
Netflix
200 201 304 400 401 403 404 412 500
Digg
200 400 401 403 404 410 500 503
你的 API 会用到多少状态码
接口通常只会返回三种结果:
一切正常 - success
应用出错 - client error
API 出错 - server error
开始使用以下三个状态码:
200 - OK
400 - Bad Request
500 - Internal Server Error
如果你需要更多状态码,加入就好了,只是要注意状态码不要超过 8 个。
如果你觉得把所有结果都归于以上三类会很不舒服,也可以从下面这 5 个中再挑几个:
201 - Created
304 - Not Modified
404 - Not Found
401 - Unauthorized
403 - Forbidden
注意: 如果有可能返回多种状态码,开发者记得要处理每条分支,这很重要!
错误信息要尽可能详细
给机器看是这样的:
200 - OK
401 - Unauthorized
给人看是这样的:
{
developerMessage: "Verbose, plain language description of the problem for the app developer with hints about how to fix it.",
userMessage:"Pass this message on to the app user if needed.",
errorCode: 12345,
moreInfo: "http://dev.teachdogrest.com/errors/12345"
}
服务即提供资源。
每个资源都有两种 base url
base url 不要包含动词
先感受一下动词的可怕:
这种形式的接口很快就会爆炸,数量会越来越多,到最后即使靠文档都很难保证不会遗漏。
使用 HTTP 动作来操作集合和元素
HTTP 动作包括 POST,GET,PUT 和 DELETE,也就是我们常说的
CRUD
(Create-Read-Update-Delete)。比如新增一个小狗:
比如删除一个小狗:
名词的单复数
从流行的 API 来看,单复数都有人使用。从用的最多的 GET 接口来看,
复数会比较好理解些
。注意:
保持接口的单复数一致
。这样开发者就不用猜某个接口是单数还是复数,提高易用性。具体名词好于抽象名词
抽象名词会使开发者搞不清接口到底能做些什么,比如:
具体名词的问题是如果太具体,资源的数量会暴增,比如小狗,具体来说会有红狗、黄狗、绿狗等。
一般资源的总数控制在
12
~24
会比较好。如果超出了这个范围,应该做适度的抽象。资源的关联性
比如小狗和人这两种资源,会产生小狗是某个人的宠物这种关系。
为了简化接口,我们可以使用查询参数,如下:
友好的错误处理
我们无法保证接口总是能正常调用,所以当程序出现异常时,应该给开发者一个友好的提示。
先来看 2 个例子:
Facebook
无法请求结果如何,统一返回 200 状态码,错误信息放到 HTTP 返回对象中。 比如 #803 error,但是没有具体的错误信息,也没说该怎么处理。
Twilio
HTTP 状态码保持一致,做得比较好的是提供了一个错误信息的文档链接,开发者可以在那里获得更多信息。
最佳实践
使用 HTTP 状态码
使用基于标准的 HTTP 状态码会比较易懂。
HTTP 状态码一共有 70 多个,但是大多数开发者都记不住那么多,如果你使用了一些不太常用的状态码,开发者就需要经常去搜某个状态码表示什么意思。
因此,大多数 API 只会使用一个小小的子集,比如 Google GData API 用到 10 个状态码,Netflix 用到 9 个,Digg 只用到 8 个。
Google Gdata
Netflix
Digg
你的 API 会用到多少状态码
接口通常只会返回三种结果:
开始使用以下三个状态码:
如果你需要更多状态码,加入就好了,只是要注意
状态码不要超过 8 个
。如果你觉得把所有结果都归于以上三类会很不舒服,也可以从下面这 5 个中再挑几个:
注意: 如果有可能返回多种状态码,开发者记得要处理每条分支,这很重要!
错误信息要尽可能详细
给
机器
看是这样的:给
人
看是这样的:总之,错误信息要尽可能友好,方便开发者调试,最好在你的错误描述中增加一个链接,提供更多的信息。
版本化
版本化是设计 Web API 最重要的思考之一。
不要公布没有版本号的 API
来看几个例子:
时间戳方案:通过时间戳找出对应版本的 API v版本号方案:我们通常比较喜欢这个方案,只是不喜欢使用 .0 的版本号,因为看起来接口会比较不稳定 v参数方案:版本号是一个可选项,不加默认使用最新版本
版本号思考
按需返回
按需返回是指开发者需要什么就返回什么,不返回没用的数据。
看几个例子:
Linkin
Facebook
Google
Google 和 Facebook 比较类似,都有一个叫做
fields
的可选参数,可以指定你需要的字段。我们一般会用
,
分割字段名。分页
offset
和limit
page
和rpp
(records per page)start
和count
Facebook 和 LinkedIn 的方式是一样的,即 offset 等价于 start,limit 等价于 count。
为了获取 50 - 75 的记录 (record),三种方式使用如下:
使用 offset 和 limit
我们推荐使用 offset 和 limit。它更常用,并且能被数据库很好的理解,同时对开发者来说也很简单。
元数据
我们也建议给翻页数据加上元数据,如记录的总数。
默认参数
我的默认参数一般是
offset=0&limit=25
。默认参数取决于你的数据量。如果数据很多,你也许会限制 limit 小于 10;如果数据很少,你就可以选择一个较大的 limit。
资源无关的接口
比如语言翻译,单位换算等都是资源无关的,不涉及读写数据库。
使用动词而不是名词
举个例子,把 100 欧元转换成人民币:
支持多种格式
我们建议你支持的格式大于一种 —— 以一种格式输出,但可以允许多种格式的输入。
来看几个例子。
Google Data
Foursquare
Digg
如果设置了 type 参数,会覆盖 Accept。
我们推荐 Foursquare 的方式。
默认格式
必须是 json 好么。
字段名
返回的数据,如何命名它的属性呢?
先看例子:
Twitter
Bing
Foursquare
每一种都有不同的编码习惯。
我们认为 Foursquare 的方式是最好的,因为返回的数据要在前端使用,而驼峰形式最符合 js 的编码习惯。
搜索
搜索某种特定资源的 api 相对比较简单,如 dogs/?q=red,但跨资源的搜索则需要不同的设计。
如果你需要跨资源的全局搜索,我们建议模仿 Google 的方式:
全局搜索
这里,search 是个动词,?q 表示 query。
限定搜索
为了限定搜索的范围,你可以在搜索前面加上范围。
举个例子,搜索 ID 是 5678 的 owner 拥有的狗