最近看了RESTful接口设计的最佳指导,这里总结下。
每个资源对应两种URL
/employees # 集合url
/employees/56 # 元素url
标示资源,使用名词而不是动词
不好的例子如下,这会导致方法数量激增,也更加复杂,后期维护麻烦。
/getAllEmployees
/getAllExternalEmployees
/createEmployee
/updateEmployee
使用http方法来操作资源。
GET /employees
GET /employees?state=external
POST /employees
PUT /employees/56
对于资源来说,4个http方法GET, POST, PUT, DELETE,来完成最常见的CRUD操作(Create新建, Read查询, Update更改, Delete删除)。
- Read: 查询某个资源,是最常见的形式,使用GET方法来查询资源。GET请求不会改变资源的任何状态,是幂等的。可以看做只读的操作,这里可以进行缓存以加快查询速度。
- Create:新建资源。使用POST方法来创建一个新的资源。
- Update:更改资源。使用PUT方法来更改一个存在的资源。
- Delete: 删除资源。使用DELETE方法来删除某个资源。
因此2个URL加上4个方法,我们就可以得到8种不同的操作。
POST (新建) | GET (查询) | PUT (更改) | DELETE (删除) | |
---|---|---|---|---|
/employees |
创建一个新的员工 | 查询所有员工 | 批量修改员工信息 | 删除所有员工信息 |
/edployees/56 |
返回错误 | 查询56号员工 | 修改56号员工信息 | 删除56号员工 |
对集合URL使用POST方法来创建一个新的资源
- 客户端使用集合URL的POST方法,HTTP body里携带新资源信息,例如员工名字Albert Stark;
- 服务端收到后,按内部逻辑保存成功后会生成该资源的唯一标示号21,返回给客户端一个成功的回复。回复包中header中包含一个Location ,表示如何访问刚刚创建的资源。客户端拿该地址,可访问刚刚新建的员工。
对元素URL使用PUT方法来修改一个资源
- 发送一个PUT请求给元素url,body中携带需要更新的内容;
- 服务端更新21号员工信息,返回状态码200和最终结果。
使用复数形式的名词
这里推荐使用复数单词。不要单数和复数混合使用。
使用查询字符来完成可选参数或复杂参数
让接口保持简单,将复杂的参数迁移到查询字符串中去。
GET /employees?state=internal&maturity=senior
使用HTTP状态码
RESTful服务可以提供一系列的HTTP状态码来标识当前请求的结果。
- 2xx,表示成功相关。
- 4xx,表示客户端错误。例如客户端参数错误,验证失效等。
- 5xx,表示服务器错误。服务器端发生错误。
2xx | 3xx | 4xx | 5xx |
---|---|---|---|
200, 成功 | 301,地址永久移动 | 400,错误请求 | 500,服务器内部错误 |
201,已创建 | 304,未改变 | 401,未认证 | |
403,禁止访问 | |||
404,资源不存在 |
提供足够的错误信息
在回复中尽量提供详细的错误信息。
请求访问高权限:
GET /employees?state=super
回复400.
// 400 Bad Request
{
"message": "You submitted an invalid state. Valid state values are 'internal' or 'external'",
"errorCode": 352,
"additionalInformation" : "http://www.domain.com/rest/errorcode/352"
}
返回的json属性使用驼峰命名法
js的客户端会常常自动将回复中的json结果转换为js的对象,使用下划线连接(year_of_birth)或大写(YearOfBirth)可能会导致出现一些问题。
person.year_of_birth //导致错误
person.YearOfBirth //构造方法
person.yearOfBirth //比较规范
在URL中强制携带版本号
在URL中强制携带一个版本号。当接口有改变时,可以部署在下一个版本中而不影响之前的旧接口。用户端可以自行选择何时迁移使用新接口,不用担心接口会时刻变化。
/v1/employees
提供分页
查询资源时,不管是对后台还是客户端,一下全部返回所有数据都不是一个好的选择。因此,需要提供分页机制。返回给客户端的结果中要包含当前分页、总共的分页等信息,以方便客户端遍历。
使用动词表示非资源型回复
有时候发起请求并不牵涉任何资源,这时候使用动词来表示更好。
GET /translate?from=de_DE&to=en_US&text=Hallo
GET /calculate?para2=23¶2=432
提供链接信息以便能在接口间访问(HATEOAS)
这里的核心思想就是提高可维护性,降低耦合性。使得客户端在后台进行URI的更改时,依然可用。
//...
{
"id":1,
"name":"Paul",
"links": [
{
"rel": "salary",
"href": "/employees/1/salaryStatements"
}
]
},
//...
上面的回复中,一个员工的信息中包含的是一个地址,而不是值。我们需要访问该地址来拿到薪水。这样多加了一层,会提供可维护性和扩展性。但会多进行网络传输。
参考: