原文:REST anti-patterns
作者:Marcelo Cure 翻译:赖信涛 责编:仲培艺
过去几年我的工作和学习一直围绕RESTful API,我在不同的项目和社区中见过很多相同的错误,于是我就决定,将我在网上读到的和我自身的经验整理一下。下面这些,是常见的一些设计错误、解释以及例子。
URI不够RESTful
你的URI没有反应相应资源的用途。
RESTful的API是基于资源的,当我们设计URI的时候,要时刻铭记我们应该通过URI正确反映资源,要让用户一看到URI,就能明白这是什么资源,是什么地方的,它的标志符是什么,它有什么可选项。
比如说,我们有种资源叫“account”,我们现在要关闭这个账户,那么相应的URI应该设计成什么呢?
下面分别是错误的和正确的例子,你认为哪一个更合理?
错误的:
- POST /accounts/close
- POST /closeAccount
正确的:
- POST /accounts/4402278/close
错误的用法没有给出URI的具体信息,也许我们需要在请求中加入一些查询的变量或主体,但是光从名字来看,并不能看到查询的参数,或需要的主体。
正确的用法明确地表达出“account” 4402278可以被关闭,从URI我们就可以推断出这一点。
使用了错误的HTTP方法
HTTP的方法必须根据请求意图的不同正确使用。例如,如果你要返回信息,就必须使用GET方法。
下面就是一些动作的类型和相应的HTTP方法:
- GET - 取回记录
- POST - 创建记录
- PUT - 更新整个记录
- PATCH - 更新其中一些记录
- DELETE - 删除记录
话虽如此,下面这种错误时常发生:
错误:
- POST /accounts/4402278/delete
正确:
- DELETE /accounts/4402278/delete
错误的例子企图在“accounts”上使用POST方法,通过在URI标注ID删除一个账户。
虽然这样做也可以达到目的,但却是不恰当的。应为HTTP提供了明确的方法来删除资源,即DELETE。
还有很多错误的例子,展开说又可以写一篇文章了,在这里只是简单提一下。
打破了幂等
无论你对相同的资源调用多少次GET,返回的信息应该不变。
- 应该维持幂等的方法:GET,PUT,OPTIONS
- 不维持幂等的方法:POST
那么DELETE方法呢?如果你删除/accounts/4402278两次会发生什么?
- 账户不应该允许被删除多次……想象一下如果维持幂等将会什么样子。
- 第二次删除操作不会找到该资源,应该返回404
https://www.youtube.com/watch?v=6dVNdFwqeKs
忽略状态码
如果你的API返回200(ok)或500(内部服务器错误),就违背了返回状态码的原则。
状态码的目的是给用户对请求状态的总体判断。
这意味着,我们应该慎重选择代表状态的状态码,它需要准确反应最后结果的状态。
错误的:
- GET /accounts/123456(没有对应记录)返回:HTTP状态200(ok),body中说没有找到
正确的:
- GET /accounts/123456(没有对应记录)返回:404(not found)
如果你需要get一个如例子所示的资源,但是没有相应的记录,那么应该返回404,因为这是not found。如果反悔200(ok)然后在body中说“not found”,这是不合适的。这种做法非常多余。
状态码也能帮助你的API更清楚地描述状态。在很多情况下,用户只处理状态码就能知道发生了什么,这比处理大型字符串更加简单。
HTTP状态码
下面是最常用的一些状态码。
- 2xx - Success
- 200 OK
- 201 Created
- 203 Partial Information
- 204 No response
- 3xx - Redirection
- 301 Moved
- 302 Found
- 304 Not Modified
- 4xx / 5xx - Error
- 400 Bad Request
- 401 Unauthorized
- 402 Payment Required
- 403 Forbidden
- 404 Not Found
- 500 Internal Server Error
- 503 Service Unavailable
忽略缓存
忽略缓存很简单,只要在API调用的头部加入”Cache-control: no-cache”就可以了。
HTTP定义了很多强大的缓存机制,包括ETag,If-Modified-Since header,和304 Not Modified返回码。
这可以让你的客户端和服务器能通过缓存或代理保持一份资源的副本,来提高应用的扩展性和性能。
忽略超链接
如果你的调用发送的描述不包含任何链接,那么你就打破了REST的HATEOAS原则。
超链接的概念指的是一些链接资源,可以让应用通过链接在不同的状态之间跳转。
如果你忽略了超链接,就意味着URI必须在客户端通过很难的编程原理实现。
更多有关HATEOAS原则
- 客户端通过链接与应用的交互应提供动态API
- 应用现在的状态由你部署的数据和链接定义
- 客户端应该对链接有一定的理解
- 服务器应该可以独立升级
- 应该通过链接来交互,而不是外带的信息
例子
在下面的例子中,我们有一个叫做“accounts”的资源,一共有一百条。
{
"accounts": [
{
"accountNumber": "4502278",
"balance": 100.00,
"links": [
{"rel": "deposit", href: "/account/4502278/deposit"},
{"rel": "withdraw", href: "/account/4502278/withdraw"},
{"rel": "transfer", href: "/account/4502278/transfer"},
{"rel": "close", href: "/account/4502278/close"}
]
}
]
}
如果现在账户出现了异常,用户只能进行其中一些操作,那么API应该如下部署:
{
"accounts": [
{
"accountNumber": "4502278",
"balance": -60.55,
"links": [
{"rel": "deposit", href: "/account/4502278/deposit"}
]
}
]
}
忽略MIME类型
如果你的API返回的资源只有一种单一的表示形式,那么可能你服务的客户端很少,而且都能理解这种形式。
如果你未来想要支持更多客户端,那么应该使用HTTP内容协商。
它可以让你指定特定的资源类型,如XML,JSON或YAML。
总结
当你设计API的时候……
- 条理清楚
- 需要头部
- 使用标准(JSON-API)
- URI设计合理
- 返回正确的状态码
- 注意幂等
- 使用正确的HTTP方法
我希望这篇文章能让你了解一下常见的错误,并且在你设计API的时候设法避免他们。
2016年9月22日-23日,[SDCC 2016大数据技术&架构实战峰会](http://bss.csdn.net/m/topic/sdcc_invite/hangzhou /)将在杭州举行,两场峰会大牛讲师来自阿里、京东、苏宁、唯品会、美团点评、游族、饿了么、有赞、Echo等知名互联网公司,共同探讨海量数据下的应用监控系统建设、异常检测的算法和实现、大数据基础架构实践、敏捷型数据平台的构建及应用、音频分析的机器学习算法应用,以及高可用/高并发/高性能系统架构设计、电商架构、分布式架构等话题与技术。
9月5日~18日是八折优惠票价阶段,5人以上团购或者购买两场峰会通票更有特惠,限时折扣,预购从速。(票务详情链接)。