[置顶] 来自 HeroKu 的 HTTP API 设计指南(中文版)
转载:http://get.jobdeer.com/343.get
来自 HeroKu 的 HTTP API 设计指南(中文版)
翻译 by @Easy
简介
本指南中文翻译者为 @Easy ,他是国内首家互联网人才拍卖网站 JobDeer.com 的创始人。转载请保留本信息。
本指南描述了一系列 HTTP+JSON API 的设计实践, 来自并展开于 Heroku Platform API 的工作。本指南指导着 Heroku 内部 API 的开发,我们希望也能对 Heroku 以外的 API 设计者有所帮助。
...
目录
基础
- 总是使用 TLS
- 在 Accepts 头中带上版本号
- 通过 Etags 支持缓存
- 用 Request-Ids 追踪请求
- 用 Ranges 来分页
请求
- 返回适当的状态码
- 总是返回完整的资源
- 在请求 body 中接收 JSON 序列
- 使用一致的路径格式
- 小写所有路径和属性
- 支持非 ID 的参数作为快捷方式
- 少用路径嵌套
响应
- 总是提供资源 (UU)ID
- 提供标准的时间戳
- 使用 ISO 8601 格式的 UTC 时间
- 嵌入外键数据
- 总是生成结构化的错误信息
- 显示频率限制的状态
- 在所有的响应中压缩 JSON 数据
文档及其他
- 提供机器可读的 JSON 格式
- 提供人类可读的文档
- 提供可执行的示例
- 描述稳定性
基础
总是使用 TLS
总是使用 TLS(就是 https)来访问 API,没有必要指出什么时候需要用,什么时候不需要用,只管任何时候都用它就好。
对所有非 TLS 的请求返回 403 Forbidden,不要用重定向,这会允许一些不良的客户端行为,而又没有任何好处。依赖重定向的客户端会使流量翻倍,而让 TLS 毫无意义 —— 敏感数据已经在第一次请求时发送出来了。
在 Accepts 头中带上版本号
从一开始就为 API 分配版本。使用 Accepts 头来发送版本信息,可以使用自定义的内容类型,如:
Accept: application/vnd.heroku+json; version=3
不要提供默认版本,而由客户端显式指定它使用哪一个特定的版本。
通过 Etags 支持缓存
在所有的请求中带上 ETag 头 , 用于识别特定版本的返回资源。用户可以在随后的请求中通过提供 If-None-Match 头的值来检查内容是否过期。
用 Request-Ids 追踪请求
在每个 API 响应中提供 Request-Id 头,带上一个唯一的 UUID 值。如果服务器和客户端都记录了这些值,在跟踪和调试请求时会派上大用场。
用 Ranges 来分页
对所有可能产生大量数据的响应进行分页。使用 Content-Range 头来标记分页请求。可以参考这个例子,来了解请求和响应头、状态码、Limit、排序和翻页:Heroku Platform API on Ranges
请求
返回适当的状态码
为每个请求返回适当的状态码,成功的请求应该遵守如下规则:
200: 当 GET 请求成功完成,DELETE 或者 PATCH 请求同步完成。
201: 同步方式成功完成 POST 请求。
202: POST,DELETE 或者 PATCH 请求提交成功,稍后将异步的进行处理。
206: GET 请求成功完成,但只返回了部分数据。参见用 ranges 分页
注意认证和认证错误的使用:
- 401 Unauthorized: 请求失败,因为用户没有进行认证。
- 403 Forbidden: 请求失败,因为用户被认定没有访问特定资源的权限。
返回合适的状态码可以为错误提供更多的信息:
- 422 Unprocessable Entity: 你的请求服务器可以理解,但是其中包含了不合法的参数。
- 429 Too Many Requests: 请求频率超配,稍后再试。
- 500 Internal Server Error: 服务器出错了,检查网站的状态,或者报告问题。
根据 HTTP response code 规范的指导来设计用户错误和服务器错误情况下的状态码。
总是返回完整的资源
对于 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}
响应
总是提供资源 (UU)ID
为每个资源提供默认的 ID 属性。除非有特殊理由,总是使用 UUID。不要用那些在服务的实例间或资源间不全局唯一的 ID,特别是自增 ID。
以 8-4-4-4-12 的格式小写 UUID:
"id": "01234567-89ab-cdef-0123-456789abcdef"
提供标准的时间戳
为资源提供默认的 created_at 和 updated_at 时间戳:
{
...
"created_at": "2012-01-01T12:00:00Z",
"updated_at": "2012-01-01T13:00:00Z",
...
}
如果这些时间戳对某些资源真的没有意义,那么你也可以去掉它。
使用 ISO 8601 格式的 UTC 时间
只接受和返回 UTC 时间,以 ISO 8601 格式显示:
"finished_at": "2012-01-01T12:00:00Z"
嵌入外键数据
将外键引用通过序列化的嵌入对象显示:
{
"name": "service-production",
"owner": {
"id": "5d8201b0..."
},
...
}
而不是这样:
{
"name": "service-production",
"owner_id": "5d8201b0...",
...
}
这使得我们可以在 inline 使用相关的数据,而不需要改变响应的格式,或者引入更多高层的响应字段:
{
"name": "service-production",
"owner": {
"id": "5d8201b0...",
"name": "Alice",
"email": "alice@heroku.com"
},
...
}
总是生成结构化的错误信息
为错误生成一致的,结构化的响应 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 算法 来量化请求限制。
在每次请求的响应头中,通过 RateLimit-Remaining 返回剩余的请求次数。
在所有的响应中压缩 JSON 数据
额外的空格增大了响应的大小,而很多人性化的客户端可以自动美化 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;)。
文档及其他
提供机器可读的 JSON 格式
提供机器可读的 schema 来描述你的 API,可以用 prmd 来管理你的 schema,用 prmd verify 来确保它通过验证。
提供人类可读的文档
提供人类可读的文档帮助客户端开发者们理解你的 API。
如果你使用了 prmd 来创建 schema,那么你可以简单的通过 prmd doc 命令来生成 Markdown 的 endpoint 级别的文档。
除了 endpoint 级别的描述,还要提供概要级别的信息,比如:
- 授权,包括获得和使用授权 Token。
- API 的稳定性和版本,包括如何选择现有的 API 版本。
- 通用请求和响应头。
- 错误的序列化格式。
- 各种语言的客户端如何使用 API 的例子。
提供可执行的示例
提供可执行的例子,这样用户可以直接在终端输入并看到可以用的 API 请求。最好的情况是,这些例子可以直接复制粘贴,以最小化用户试用 API 的成本,如:
$ export TOKEN=... # acquire from dashboard
$ curl -is https://$TOKEN@service.com/users
如果你使用 prmd 来生成 Markdown 文档,你就免费获得了可执行的示例。
描述稳定性
描述你 API 的稳定性,以及哪些 endpoint 依赖于其成熟度,比如使用 prototype,development 或者 production 的标识。
可参考 Heroku API compatibility policy 了解哪些接口是稳定的,哪些可能有变动。
一旦你的 API 宣布为 production-ready 和 稳定版,不要在该 API 版本上做任何不向前兼容的修改。如果你需要做不向前兼容的修改,创建一个新的版本号。
本文由 Easy 发表于GET
[置顶] 来自 HeroKu 的 HTTP API 设计指南(中文版)的更多相关文章
- 来自HeroKu的HTTP API 设计指南(中文版)
原文转自:http://get.jobdeer.com/343.get 来自HeroKu的HTTP API 设计指南(中文版) 翻译 by @Easy 简介 本指南中文翻译者为 @Easy ,他是国内 ...
- Google API Design Guide (谷歌API设计指南)中文版
面向资源的设计 这份设计指南的目标是帮助开发人员设计简单.一致.易用的网络API.同时,它也有助于收敛基于socket的API和(注:原文是with,这里翻译为“和”)基于HTTP的REST API. ...
- HTTP API 设计指南(中文版) restfull
http://www.css88.com/archives/5121 目录 基础 总是使用TLS 在Accepts头中带上版本号 通过Etags支持缓存 用Request-Ids追踪请求 用Range ...
- HTTP API 设计指南(请求部分)
为了保证持续和及时的更新,强烈推荐在我的Github上关注该项目,欢迎各位star/fork或者帮助翻译 前言 这篇指南介绍描述了 HTTP+JSON API 的一种设计模式,最初摘录整理自 Hero ...
- HTTP API 设计指南(响应部分)
前言 这篇指南介绍描述了 HTTP+JSON API 的一种设计模式,最初摘录整理自 Heroku 平台的 API 设计指引 Heroku 平台 API 指引. 这篇指南除了详细介绍现有的 API 外 ...
- HTTP API 设计指南(结尾)
前言 这篇指南介绍描述了 HTTP+JSON API 的一种设计模式,最初摘录整理自 Heroku 平台的 API 设计指引 Heroku 平台 API 指引. 这篇指南除了详细介绍现有的 API 外 ...
- HTTP API 设计指南(基础部分)
前言 这篇指南介绍描述了 HTTP+JSON API 的一种设计模式,最初摘录整理自 Heroku 平台的 API 设计指引 Heroku 平台 API 指引. 这篇指南除了详细介绍现有的 API 外 ...
- Rest Framework简介 和 RESTful API 设计指南
使用Django Rest Framework之前我们要先知道,它是什么,能干什么用? Django Rest Framework 是一个强大且灵活的工具包,用以构建Web API 为什么要使用Res ...
- RESTful API 设计指南 (转)
RESTful API 设计指南 2016-02-23 ImportNew (点击上方公号,可快速关注) 作者:阮一峰 链接:http://www.ruanyifeng.com/blog/2014/0 ...
随机推荐
- BA-WG-冷源
冷源群控系统最好由冷源厂家来做的理由 1.冷机厂家对空调的参数十分的清楚,明确的知道冷机的负荷曲线,可以优化冷机加减载的最合理时间达到最佳的节能效果 2.独立的CSM硬件模块,内置不同冷机的型号特性, ...
- jQuery学习之开篇
吐槽 近期比較烦,对于一个前端白痴来说,工作方向突然转向前端这块着实让人蛋疼无比.前段时间简单的学习了下EasyUI,算是对其有一个简单的认知了吧.EasyUI的研究过程中发现,假设没有掌握JS.JQ ...
- 一种加快在苹果app store中上架的方法
预计近期苹果app应用上架的比較多,审核比較慢,如今一个app从提交到上架短则7.8天.长则2.3个星期.我在实际上线应用时,总结了一个简单有用的小技巧,能够加快上架时间,近期使用这样的方法后.我们基 ...
- 开发,从需求出发 · 之四 春天在这里
首先,我要大字标语表达立场: 你所使用的framework & non-core features,就跟女人穿在身上的衣服一样,越少越好! watermark/2/text/aHR0cDovL ...
- fastjson null 值处理
偶然用到fastjson转换json 在前台用js解析竟然某些字段没有,曾经用过gson.联想到是不是相似gson默认将null值不显示了,找了下资料果真如此 直接上代码吧 import java.u ...
- linux下怎样将sheduler绑定到制定的cpu核上
作者:张昌昌 1.顺序绑定 erl +sbt db 是按从前到后的顺序来绑定调度器的,如: erl +sbt db +S 3含义是启动erlang虚拟机,开启3个调度器,按顺序绑定在0,1.2号核 ...
- React-Native Android开发沉思录
在runServer.js中有声明如何启动http服务: 查看端口占用情况 而且在系统管理器中,根本找不到PID为7956的应用,那能更改端口吗?在server.js中有声明: module.expo ...
- MySQL视图、触发器、事务、存储过程、函数
视图.触发器.事务.存储过程.函数 阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 一 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据 ...
- HBase编程 API入门系列之modify(管理端而言)(10)
这里,我带领大家,学习更高级的,因为,在开发中,尽量不能去服务器上修改表. 所以,在管理端来修改HBase表.采用线程池的方式(也是生产开发里首推的) package zhouls.bigdata.H ...
- JavaWeb中使用到的类与接口整理(一)servlet包
javaweb学了半本,整理了一下Servlet技术模型.servlet容器模型.jsp技术模型中的类与接口,有助于理解web应用中的页面跳转和参数传递,目录: HttpServlet 可作Scope ...