HTTP-API-DESIGN 怎样设计一个合理的 HTTP API (二)
2015-06-23 12:02
537 查看
接上篇
这一篇主要从服务端应该如何返回合理的返回值的角度,讨论如何设计一个合理的 HTTP-API;
主要有以下几个方面:
为每个资源,分配一个 Resource ID(UUID)
使用统一的时间戳
正确地使用外键
将错误响应信息标准化
对客户端进行流量控制
将发返回的 JSON “最小化”
避免使用自增 ID 主要从以下几个方面考虑:
数字 ID 会暴露总体用户量
数字 ID 会使数据抓取变得更容易
数字 ID 会有溢出的潜在风险
数字 ID 会(不自觉地)使你的代码和 DB 耦合
有些人(比如我)更喜欢用unix 时间戳,其实这些习惯,更多的出于对 datetime 库的不熟悉导致的。使用 UTC 的优点还是很多的:
为什么不使用 UNIX 时间戳? 不可读,不方便
除了这点呢?后台调试不方便(sql select)
会有性能问题吗?不会大到影响你的程序
我不会用? 找对应语言的 lib
比如这样:
下面的方式是错误的:
上面两种方式有什么区别呢? 假设有一天,由于业务需要,你想在结果中,增加一些额外的信息,独立外键的方式,可以很清晰地、不影响原有结果格式地完成任务:
而非独立外键,要么需要增加好多不明的key;要么需要修改原有的数据格式。
一般在 header中,返回 resource uri; 在 body 中,要明确标识出错误的 id、提示信息以及请求的 url。
服务端返回“RateLimit-Remaining” 相关信息,客户端根据“RateLimit-Remaining” 的结果,来延长或缩短某些请求的间隔。
比如这样:
那怎么调试呢?可以参考 elastic_search 的实现,让 server 支持一个 pretty 参数,如果在 url 中增加“ pretty=true”, 那么返回的 json 结果将是格式化好、便于阅读的格式。
简略地说,作为一个 API 的 Server 端,应该做到:
负责人需要 “头脑清醒考虑之”
撰写清晰的文档,并且需要与服务保持更新
自己负责测试(将测试代码一并提交)
提供良好的联调环境
使用Resource-ID、Status Code、Rate Limit、pretty 等方式方便调试
代码要做到 “宽入严出”
为一个 API 的使用者,应该做到:
读文档,读文档,读文档
先读文档,再找 Server RD
文档中存疑的部分,拒绝猜测的诱惑
按照文档的描述,而不是自己的经验来调用 API
正确地处理各种服务端的异常 case
代码要做到 “宽入严出”
HTTP-API-DESIGN 怎样设计一个合理的 HTTP API (一)
整个 ppt 可以去这里下载。这一篇主要从服务端应该如何返回合理的返回值的角度,讨论如何设计一个合理的 HTTP-API;
主要有以下几个方面:
为每个资源,分配一个 Resource ID(UUID)
使用统一的时间戳
正确地使用外键
将错误响应信息标准化
对客户端进行流量控制
将发返回的 JSON “最小化”
为每个资源,分配一个 Resource ID(UUID)
返回的结果中,需要为每一个“资源”(用户、消息、评论、私信等等)分配一个唯一的 ID(UUID)。 推荐使用 “8-4-4-4-12” 格式的 UUID,一定不要使用数字,尤其是自增 ID。避免使用自增 ID 主要从以下几个方面考虑:
数字 ID 会暴露总体用户量
数字 ID 会使数据抓取变得更容易
数字 ID 会有溢出的潜在风险
数字 ID 会(不自觉地)使你的代码和 DB 耦合
使用统一的时间戳
继续“资源” 的话题,当我们创建、修改资源时,都需要记录下操作对应的时间。应该在 DB 中,为每一个资源,提供“created_at”', “updated_at”' 信息; 存储、传输时间信息时,应该使用 “ISO8601”格式化过的 “UTC”'(only), 不应该使用其他格式存储时间。有些人(比如我)更喜欢用unix 时间戳,其实这些习惯,更多的出于对 datetime 库的不熟悉导致的。使用 UTC 的优点还是很多的:
为什么不使用 UNIX 时间戳? 不可读,不方便
除了这点呢?后台调试不方便(sql select)
会有性能问题吗?不会大到影响你的程序
我不会用? 找对应语言的 lib
正确使用外键
在 API 返回的结果中,如果某个结果中涉及到了其他“资源”,应该独立标识出它的外键。比如这样:
{ "name": "service-production", "owner": { "id": "5d8201b0-xxx" } }
下面的方式是错误的:
{ "name": "service-production", "owner_id": "5d8201b0-xxx" }
上面两种方式有什么区别呢? 假设有一天,由于业务需要,你想在结果中,增加一些额外的信息,独立外键的方式,可以很清晰地、不影响原有结果格式地完成任务:
{ "name": "service-production", "owner": { "id": "5d8201b0...", "name": "Alice", "email": "alice@heroku.com" } }
而非独立外键,要么需要增加好多不明的key;要么需要修改原有的数据格式。
将错误响应信息标准化
当某次请求出现错我的时候,需要同时在 header、body 中附上必要的信息,方便API 的调用者清楚问题在哪里。一般在 header中,返回 resource uri; 在 body 中,要明确标识出错误的 id、提示信息以及请求的 url。
{ "id": "rate_limit", "message": "Account reached its API rate limit.", "url": "https://docs.service.com/rate-limits" }
流量控制
随着用户逐渐增多,一定会出现,客户端请求量变大导致服务器无法响应的情形,此时维护服务的稳定,就变成了服务端、客户端共同的责任。需要约定一套机制,让客户端能够感知到服务端目前的状况,合理安排自身逻辑。 一个合理的解决方案是:利用“RateLimit-Remaining”。服务端返回“RateLimit-Remaining” 相关信息,客户端根据“RateLimit-Remaining” 的结果,来延长或缩短某些请求的间隔。
Keep JSON minified
为了流量考虑,应该将生成的JSON,剔除空格、换行后返回给客户端。比如这样:
{"beta":false,"email":"alice@heroku.com","id":"01234567-89ab-cdef-0123-456789abcdef","last_login":"2012-01-01T12:00:00Z","created_at":"2012-01-01T 12:00:00Z","updated_at":"2012-01-01T12:00:00Z"}
那怎么调试呢?可以参考 elastic_search 的实现,让 server 支持一个 pretty 参数,如果在 url 中增加“ pretty=true”, 那么返回的 json 结果将是格式化好、便于阅读的格式。
总结
流水帐似的写了这么多,总结一下吧。简略地说,作为一个 API 的 Server 端,应该做到:
负责人需要 “头脑清醒考虑之”
撰写清晰的文档,并且需要与服务保持更新
自己负责测试(将测试代码一并提交)
提供良好的联调环境
使用Resource-ID、Status Code、Rate Limit、pretty 等方式方便调试
代码要做到 “宽入严出”
为一个 API 的使用者,应该做到:
读文档,读文档,读文档
先读文档,再找 Server RD
文档中存疑的部分,拒绝猜测的诱惑
按照文档的描述,而不是自己的经验来调用 API
正确地处理各种服务端的异常 case
代码要做到 “宽入严出”
相关文章推荐
- 用Tomcat服务器配置https双向认证过程实战
- sharepoint HttpModule实现方式
- 面向物联感知终端的Java网络编程 (一)
- socket编程-- 基于TCP协议的网络程序
- 网络编程 C++ ———MFC Socket
- MFC 网络编程
- 【Android笔记】不能在主线程中进行网络操作
- 使用Node.js实现HTTP 206内容分片的教程
- vc 网络编程(socket)
- java网络笔记
- 在Node.js中使用HTTP上传文件的方法
- HTTP请求响应状态码详解
- java中HttpServletRequest可获取的URI方法介绍
- 笔记_网络03
- 【网络协议】TCP交互数据流和数据流成块
- 一、网络基础
- 软件定义网络、网络虚拟化和网络功能虚拟化的区别
- TCP的流量控制与拥塞控制
- 安卓网络编程——使用HttpURLConnection
- 安卓网络编程——webView加载有道网页