本文档提供了白宫Web API的指南和示例,鼓励跨前后端的一致性,可维护性和最佳实践。白宫API旨在平衡真正的RESTful API接口和积极的开发者体验(DX)。该文件大量借鉴:
- 设计HTTP接口和RESTful Web服务
- API Facade Pattern,作者:Brian Mulloy,Apigee
- Web API设计,作者:Brian Mulloy,Apigee
- 菲尔丁关于REST的论文
这些指南旨在支持真正的RESTful API。以下是一些例外情况:
- 将API的版本号放在URL中(参见下面的示例)。不接受任何未指定版本号的请求。
- 允许用户像这样请求JSON或XML等格式:
- http://example.gov/api/v1/magazines.json
- http://example.gov/api/v1/magazines.xml
RESTful URL的一般准则
- URL标识资源。
- 网址应包含名词,而不是动词。
- 使用复数名词只是为了一致性(没有单数名词)。
- 使用HTTP谓词(GET,POST,PUT,DELETE)对集合和元素进行操作。
- 不应该比资源/标识符/资源更深嵌套了。
- 将版本号放在URL的尾部,例如http://example.com/v1/path/to/resource。
- URL 和Header的选择:
- 如果更改了你编写的逻辑以处理响应,请将其放入URL中。
- 如果它没有更改每个响应的逻辑,例如OAuth信息,请将其放在标题Header中。
- 在逗号分隔列表中指定可选字段。
- 格式应采用api/v2/resource/{id} .json的形式
好的URL示例
- 杂志资源列表:
- GET http://www.example.gov/api/v1/magazines.json
- 过滤是一种查询:
- GET http://www.example.gov/api/v1/magazines.json?year=2011&sort=desc
- GET http://www.example.gov/api/v1/magazines.json?topic=economy&year=2011
- JSON格式的一个杂志资源:
- GET http://www.example.gov/api/v1/magazines/1234.json
- 本杂志中的所有文章(或属于本杂志):
- GET http://www.example.gov/api/v1/magazines/1234/articles.json
- 本杂志中的所有文章都是XML格式:
- GET http://example.gov/api/v1/magazines/1234/articles.xml
- 在逗号分隔列表中指定可选字段:
- GET http://www.example.gov/api/v1/magazines/1234.json?fields=title,subtitle,date
- 在特定杂志中添加新文章:
- POST http://example.gov/api/v1/magazines/1234/articles
错误的URL示例
- 非复数名词:
- http://www.example.gov/magazine
- http://www.example.gov/magazine/1234
- http://www.example.gov/publisher/magazine/1234
- 网址中的动词:
- http://www.example.gov/magazine/1234/create
- 在查询字符串之外过滤
- http://www.example.gov/magazines/2011/desc
HTTP动词
应使用HTTP谓词或方法,以符合HTTP / 1.1标准下的定义。动作时与正在处理的媒体类型及其当前状态有关。以下是HTTP谓词如何映射到特定上下文中的创建,读取,更新,删除操作的示例:
/dogs
POST: 创建一个狗
GET: 列表
UPDATE:更新
DELETE:删除所有
响应
- key中不能有值
- 不能有内部特定的名称(例如“node”和“taxonomy term分类术语”)
- 元数据应仅包含响应集的直接属性,而不包含响应集成员的属性
"键中没有值"的好例子
"tags": [ {"id": "125", "name": "Environment"}, {"id": "834", "name": "Water Quality"} ], |
"键中有值"的坏例子
"tags": [ {"125": "Environment"}, {"834": "Water Quality"} ], |
错误处理
错误响应应包括常见的:HTTP状态代码,开发人员的消息,最终用户的消息(适当时),内部错误代码(对应于某些特定的内部确定的ID),开发人员可以找到更多信息的链接。
例如:
{ "status" : 400, "developerMessage" : "Verbose, plain language description of the problem. Provide developers suggestions about how to solve their problems here", "userMessage" : "This is a message that can be passed along to end-users, if needed.", "errorCode" : "444444", "moreInfo" : "http://www.example.gov/developer/path/to/help/for/444444, http://drupal.org/node/444444", } |
使用三个简单的常见响应代码表示(1)成功,(2)由于客户端问题导致的故障,(3)由于服务器端问题导致的故障:
200 - 好的
400 - 错误请求
500 - 内部服务器错误
版本
- 永远不要在没有版本号的情况下发布API。
- 版本应为整数,而不是十进制数,前缀为“v”。例如:
- 好:v1,v2,v3
- 差:v-1.1,v1.2,1.3
- 维护至少一个版本的API。
记录限制
- 如果未指定限制,则返回默认限制。
- 要获得记录51到75,请执行以下操作:
- http://example.gov/magazines?limit=25&offset=50
- offset = 50表示'跳过前50条记录'
- limit = 25表示'最多返回25条记录'
有关记录限制和总可用计数的信息也应包含在响应中。例:
{ "metadata": { "resultset": { "count": 227, "offset": 25, "limit": 25 } }, "results": } |
请求和响应示例
API资源
- GET /magazines
- GET /magazines/[id]
- POST /magazines/[id]/articles
GET /magazines
Example: http://example.gov/api/v1/magazines.json
响应体:
{ "metadata": { "resultset": { "count": 123, "offset": 0, "limit": 10 } }, "results": [ { "id": "1234", "type": "magazine", "title": "Public Water Systems", "tags": [ {"id": "125", "name": "Environment"}, {"id": "834", "name": "Water Quality"} ], "created": "1231621302" }, { "id": 2351, "type": "magazine", "title": "Public Schools", "tags": [ {"id": "125", "name": "Elementary"}, {"id": "834", "name": "Charter Schools"} ], "created": "126251302" } { "id": 2351, "type": "magazine", "title": "Public Schools", "tags": [ {"id": "125", "name": "Pre-school"}, ], "created": "126251302" } ] } |
GET /magazines/[id]
Example: http://example.gov/api/v1/magazines/[id].json
响应体:
{ "id": "1234", "type": "magazine", "title": "Public Water Systems", "tags": [ {"id": "125", "name": "Environment"}, {"id": "834", "name": "Water Quality"} ], "created": "1231621302" } |
POST /magazines/[id]/articlesExample: Create – POST http://example.gov/api/v1/magazines/[id]/articles
响应体:
[ { "title": "Raising Revenue", "author_first_name": "Jane", "author_last_name": "Smith", "author_email": "jane.smith@example.gov", "year": "2012", "month": "August", "day": "18", "text": "xxxxxxx.. " } ] |
模拟响应
建议每个资源在测试服务器上接受'mock'参数。传递此参数应返回模拟数据响应(绕过后端)
。在开发早期实现此功能可确保API表现出一致的行为,支持测试驱动的开发方法。注意:如果mock参数包含在对生产环境的请求中,则应引发错误。
JSONP
解释JSONP最简单是用一个例子。这是StackOverflow中的定义:
假设您在域名abc.com上,并且您想向域xyz.com发出请求。要做到这一点,你需要跨越域边界,在大多数浏览器领域都是禁忌。绕过此限制的一个项目是标签。
当您使用这个脚本标签时,跨域限制将被忽略,但在正常情况下,您无法对结果做任何事情,只会对脚本进行评估。
当你向启用了JSONP的服务器发出请求时,你会传递一个特殊参数,告诉服务器一些关于您的页面的信息。这样,服务器就能够以您的页面可以处理的方式很好地包装其响应。例如,假设服务器需要一个名为“callback”的参数来启用其JSONP功能。然后你的请求看起来像:
http://www.xyz.com/sample.aspx?callback=mycallback
如果没有JSONP,这可能会返回一些基本的javascript对象,如下所示:
{ foo: 'bar' }
但是,使用JSONP时,当服务器收到“callback”参数时,它会以不同的方式包装结果,返回如下内容:
mycallback({ foo: 'bar' });
如您所见,它现在将调用您指定的方法。因此,在您的页面中,您定义了回调函数:
mycallback = function(data){ alert(data.foo); };