HTTP Methods 和 RESTful API 的设计
平日里做系统基本少不了RESTful API的设计与使用,可是却一直没有认真总结一下。今天从HTTP Methods开始,来记录下平时设计RESTful API的一些规则(个人理解,谈不上原则)。
HTTP的一个插曲
HTTP我们都知道是“超文本传输协议”,但是如果读过Roy Fielding博士的那篇有关REST的论文,应该对其中两句话印象比较深刻(我也就记得这两句)
HTTP is not RPC
HTTP is not a Transport Protocol
HTTP的全称,Hyper Text Transfer Protocol,论文中指出之所以说不是一种“传输”协议,是因为HTTP强调的是通过执行资源表述的转移(移交)和操作等各种动作,使消息反映出网络架构的语义。总之这个协议不只是传输资源而已,可能这个协议叫做超文本转移协议更合适。知道有这么回事儿就好了,不影响我们使用,学术上的严谨性就搁置一旁了。
REST解释:Representational state transfer,译本比较多,有表述性状态传递,有表达性状态转换等等。它描述的是一种架构风格。
HTTP Methods概述
HTTP Methods本身是比较多的,与我们定义RESTful API相关的通常是GET、POST、PUT、PATCH、DELETE。我们来分别看一下这几个方法的定义。
GET方法仅用于对资源表述/信息的检索请求,不能对其进行任何更改。GET方法应该是安全并且幂等的。幂等性主要指多次执行结果应该一致,比如检索一个产品信息,当产品本身没有变化的情况下,无论执行多少次GET请求得到的同样的结果。在HTTP状态码使用上,GET请求通常使用200状态码表示找到相应的资源,404表示找不到相应资源,400表示错误请求。
POST方法用来创建新的(次级)资源。POST方法既不安全也不幂等。如果创建资源成功使用201状态码表示,如果未创建相应资源可用200或204表示。
PUT方法用来更新已有资源(如果资源不存在,可决定是否创建资源)。注意这个更新是对资源整个更新。PUT方法是非安全但是幂等的。如果是创建了新的资源则使用201状态码,如果是已有资源被修改使用200或204表示。
PATCH方法对已有资源的部分进行修改。PATCH方法不安全但是幂等。如果资源更新成功使用200或204状态码表示,如果资源不存在使用404表示,如果该操作不被允许使用405表示。
DELETE方法用于删除资源。如果删除成功并且有返回描述使用200表示,如果操作被接受但尚在排队状态使用202,如果执行成功但无返回描述使用204表示, 要删除的资源不存在使用404表示,操作不被允许使用405表示。
RESTful API第一阶段
HTTP Methods与RESTful API相关的几个方法到这里就做了初步的说明,现在看看我们平时怎么设计API的。
在这方面我们经历过两个阶段,一个阶段是仅使用到GET和POST,GET比较好理解,查询类的都使用GET方法。而其他的增删改使用POST方法。这一阶段主要将资源做出了区分,并没有严格地按照对应的HTTP Method执行相应的操作。
这个阶段始于早期使用RESTful接口的时候,也倾向于简单处理,除了常规的获取对象列表与单个对象使用GET外,其余都使用POST请求,只是在URI上加上了要执行操作的定义,为表达的通用性URI上的可变部分用“{}”表示,当然不同实现下对于可变部分的定义不同,如用“:”表示,这里可理解即可。比如:
http(s)://host/products/list
http(s)://host/products/get/{id}
http(s)://host/products/delete/{id}
或者把get、delete这样的操作定义放在对象名之前。
RESTful API第二阶段
之后再设计API时尽可能地遵循了REST设计的建议,区分各种操作对应的HTTP方法,并明确在服务端校验。
这个阶段会约定的更为细致一些,对使用什么HTTP方法及URI如何定义及返回码都做了相应的规约。
URI总的约定
首先是URI的一个总的约定,因为操作类型通过HTTP Methods确定,所以URI上不再体现操作,URI主体部分由服务器地址+版本号+对象名复数形式+参数这样的形式定义。
如:http(s)://host/1.0.0/users/123
如果URI的定义不能充分表明意图,则在URI中加入操作的定义以更明确,如对于展示列表有两个需要参数的URI定义,一个是简单的传递页数与每页记录数,另一个则是需要传递一个复杂的查询参数对象进行,则可以进一步做URI的区分如下:
http(s)://host/1.0.0/users/2/20
http(s)://host/1.0.0/users/query
HTTP GET:
用于处理获取资源列表、确定的资源等请求,对于简单的多参数使用路径参数的形式。如:http(s)://host/1.0.0/users/{id}
http(s)://host/1.0.0/users/{phone}
http(s)://host/1.0.0/users/{page}/{limit}
对于状态码,会与之前介绍HTTP Methods时有些差异,差异在对于获取不到相应资源的状态码,通常我们在系统中不使用404,404一般统一在系统级别进行处理,所以并不希望在请求的URI合法的情况下只是无结果而用404状态表示。所以对于GET请求通常使用200状态返回(如想区分无内容返回的情况可使用204来代替)。后面的情况相同,404均不作为业务合法情况下的返回码。对于其他40X的请求状态使用服务器默认状态并作统一处理。
HTTP POST:
用于处理资源的新增。如:
http(s)://host/1.0.0/users
新增成功返回状态码201,未创建资源使用200。
HTTP PUT:
用于处理资源的更新。通常我们不在PUT中进行新增操作,即发现资源不存在不进行新增,在API的定义上语义区分更严格一些。如:
http(s)://host/1.0.0/user/{id}
需要注意的是采用PUT方法是对资源的全局修改。更新成功返回200状态码(如果要区分更新成功但不返回任何说明性描述或未更新也可使用204进一步明确)。
说明:如果仍在使用Form提交的方式,需要注意Form本身只支持GET和POST请求,在使用PUT、PATCH、DELETE提交Form时需要做些特殊的处理。现在RESTful的API更倾向使用JSON这类格式提交,则不存在上述问题。
HTTP PATCH:
用于处理资源的局部更新请求。如:
http(s)://host/1.0.0/users/{id}
执行成功返回200。
HTTP Delete:
用于处理资源的删除请求。如:
http(s)://host/1.0.0/users/{id}
删除成功返回200状态码。
对于状态码的定义上再多做一些说明,我们在使用中通常只有新增成功时会使用201的状态码,其余请求执行正常的情况下均使用200状态码,至于请求执行的结果依据业务情况在逻辑失败的情况下返回相应信息。至于其他2XX的状态码较少应用。
如上则是我们通常定义RESTful API的一些方式,在API的定义上比较重要的是在团队内形成一致的认知,在既有系统内维持统一的规约。
最后提一下HATEOAS
HATEOAS(Hypermedia as the engine of application state),是REST架构风格的一个最复杂的约束。Richardson提出了REST的成熟度模型,分为四级,而这四级中的最高级就是符合HATEOAS约束。我们通常比较容易满足到第三级,即用不同的HTTP Method执行不同的操作请求,就像我们上面第二阶段定义的一样。而HATEOAS则要求为客户端返回引导性的链接,可让客户端在一个请求成功后知道可以进行哪些其他请求。直观的理解就是返回结果中包含了其他的URI,调用方可以根据情况后续执行何种请求。对于这一块我也只做了个大概的了解,就不展开了,如果确实需要实现到这个级别,可以查阅相关的资料。
版权声明: 本文为 InfoQ 作者【孙苏勇】的原创文章。
原文链接:【http://xie.infoq.cn/article/96ec5efabb7f1a2d055b5332e】。文章转载请联系作者。
评论