准备知识
HTTP的头域包括四个部分:
- 通用头:通用头部是客户端和服务器都可以使用的头部,可以在客户端、服务器和其他应用程序之间提供一些非常有用的通用功能,如Date头部
- 请求头:请求头部是请求报文特有的,它们为服务器提供了一些额外信息,例如客户端希望接收什么类型数据的Accept头部
- 响应头:响应头部便于客户端提供信息,例如表示客服端在与哪种类型的服务器进行交互的Server头部
- 实体头:实体头部指的是用于实体主体部分的头部,例如表示主体部分内容类型的Content-Type头部
设计RESTful API之前,必须了解的几个HTTP头信息:
- Accept:请求头,表示发送端(客户端)希望接收的数据类型,比如: Accept: application/json, text/json
- Content-Type:实体头,表示发送端(客户端 或 服务端)发送的实体数据类型,比如 Content-Type: text/html; charset=UTF-8
REST概念
略… …
设计准则
1 版本
API的版本在设计时应该强制性要求,这样未来更改API结构时,不会破坏旧版本的兼容。版本常用的设计方式有两种:
- 一种设计方式是版本号作为URL的一部分,例如: api.jd.com/uchance/v1/…
- 另一种方式比较巧妙,也是推荐的做法,使用Accept HTTP请求头传递版本信息,Github就是这么做的: Accept: application/vnd.github.v3+json
2 命名
在对资源命名时要使用名词,不要使用动词。HTTP提供的GET、POST、PUT、DELETE方法让你可以操作数据:
- GET api.jd.com/uchance/products # 获取产品列表
- POST api.jd.com/uchance/products # 添加产品
- PUT api.jd.com/uchance/products/1 # 修改ID为1的产品
- DELETE api.jd.com/uchance/products/1 # 删除ID为1的产品
3 单数还是复数
在资源命名时要使用名词的复数,不然单数、复数混合很快会变的混乱和不一致,即使POST、PUT、DELETE也应该使用复数。
4 嵌套资源
当我们想获取一个资源集合的子集合时,应该进行嵌套设计。例如我们要获取订单列表:
- GET api.jd.com/uchance/products/1/orders # 以产品维度,获取产品编号为1的所有订单列表
- GET api.jd.com/uchance/users/1/orders # 以用户维度,获取用户编号为1的所有订单列表
5 分页
当返回的数据量比较大时,我们需要分页,分页的做法一般是作为HTTP参数传递:
- GET api.jd.com/uchance/products?page=1&limit=20 # 获取产品列表,页码为1,每页显示20条
6 状态码
返回内容(成功或失败)时,应当使用合适的HTTP状态码,GO专享因为微信端的历史原因,没有完全按照HTTP Status Codes规范。
下边是一些常用的HTTP状态码:
- 成功时的状态码
200:成功,表示服务器已经成功处理了请求
201:创建,表示服务器执行成功,并且创建了新的资源
202:已接受,表示服务器已经接受了请求,当请求排队等待进行后台处理时,应该使用它(异步任务)
204:空内容,应该在请求被正确执行,但没有返回任何内容时使用(例如当你删除某些东西)
… …
- 失败时的状态码
400:错误请求,当请求参数或内容有误时使用
401:无权限,当请求没有权限时使用
403:被进制,当请求成功(有权限401),但是操作被禁止(比如没有DELETE权限)
406:不接受,当请求的内容不被服务器接受时,例如服务器接受XML,但客户端提交的是JSON
410:结束,当请求的资源被永久删除时返回
422:验证错误,当创建对象时发生验证错误
… …
设计误区
下边是一些错误的设计示例:
- GET api.jd.com/uchance/product # 使用单数的资源名称
- GET api.jd.com/uchance/products/1?limit=20 # 分页参数不能作为资源
- POST api.jd.com/uchance/products/create # 使用动词命名资源
设计实例
请求设计示例:
- GET api.jd.com/uchance/products?page=1&limit=20&type=1 # 获取产品列表,过滤参数为page=1、limit=20、type=1
- GET api.jd.com/uchance/products/1 # 获取编号为1的产品
- GET api.jd.com/uchance/products/form # 获取产品新建页数据
- POST api.jd.com/uchance/products # 新建产品(提交产品新建数据)
- GET api.jd.com/uchance/products/1/form # 获取产品编号为1的修改页数据
- PUT api.jd.com/uchance/products/1 # 修改产品编号为1的产品(提交产品修改数据)
- DELETE api.jd.com/uchance/products/1 # 删除产品编号为1的产品
该文档参考了以下链接:
https://developer.github.com/guides/traversing-with-pagination/
https://developer.github.com/v3/media/#request-specific-version