restful最佳实践

使用名词,而不是动词

推荐

资源 GET/read POST/create PUT/update DELETE
/cars 获取所有车辆信息 新建一辆车 批量更新车 删除所有车
/cars/711 获取某一指定车辆 不允许(405) 更新某一指定车辆 删除某一特定车辆

不推荐

1
2
3
/getAllCars
/createNewCar
/deleteAllRedCar

不应该使用GET和查询参数改变状态

推荐

1
使用POST、PUT、DELETE替代GET

不推荐

1
2
GET /users/711?active
GET /users/711/active

使用名词的复数形式

不要混合使用名词的单数和复数。仅仅使用名词的复数形式代表所有资源

推荐

1
2
3
4
/cars
/users
/products
/settings

不推荐

1
2
3
4
/car
/user
/product
/setting

使用子资源进行关联

如果资源与另一资源相关,使用子资源

1
2
3
4
//获取开711车的所有驾驶员信息
GET /cars/711/drivers
//获取开711车的驾驶员为4的信息
GET /cars/711/drivers/4

使用HTTP请求/响应头序列化格式

用于规定服务端与客户端双方的通信格式

1
2
Content-Type 定义请求格式
Accept: 定义响应格式

使用HETEOAS

Hypermedia as the Engine of Application State

在API中使用超链接创建更好的导航

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"id": 711,
"manufacturer": "bmw",
"model": "X5",
"seats": 5,
"drivers": [
{
"id": "23",
"name": "Stefan Jauker",
"links": [
{
"rel": "self",
"href": "/api/v1/drivers/23"
}
]
}
]
}

为集合提供筛选,排序,字段选择和分页

  • 筛选
1
2
GET /cars?color=red //获取颜色为红色的车辆列表
GET /cars?seats<=2 //获取座位数不超过2个的车辆列表
  • 排序
1
GET /cars?sort=-manufactorer,+model //获取根据制造商降序、型号升序排序的车辆列表
  • 字段选择

    客户端不需要展示一个资源的所有属性,让客户端可以自己选择返回的字段,减少网络流量,提高速度

1
GET /cars?fields=manufacturer,model,id,color
  • 分页

使用limit和offset,默认值limit=20,offset=0

1
GET /cars?offset=10&limit=5

总条数使用HTTP头:X-Total-Count

1
X-Total-Count: 100

上一页下一页链接使用HTTP头:Link,而不是自己构建链接

1
2
3
4
Link: <http://127.0.0.1/api/v1/cars?offset=15&limit=5>; rel="next",
<http://127.0.0.1/api/v1/cars?offset=50&limit=3>; rel="last",
<http://127.0.0.1/api/v1/cars?offset=0&limit=5>; rel="first",
<http://127.0.0.1/api/v1/cars?offset=5&limit=5>; rel="prev"

版本化API

将API版本设为必选,不发布未版本控制的API。使用简单的序数,并在前面加上v,避免使用点表示法(2.5)

1
/api/v1

使用HTTP状态玛表示错误

码表,使用一些常用的状态码,而非全部

状态码 描述 解释
200 OK 一切正常
201 OK 创建新资源
204 OK 资源被成功删除
304 Not Modified 客户端可以使用缓存数据
400 Bad Request 无效请求,确切的错误在错误返回中说明。如,“JSON是无效”
401 Unauthorized 要求用户验证
403 Forbidden 服务端识别该请求,但拒绝或无权访问
404 Not found 无对应的URI
422 Unprocessable Entity 服务器无法处理实体,例如,图像无法格式化或缺少必填字段
500 Internal Server Error 开发人员应避免此错误。如果错误被全局捕捉到,堆栈信息应记录在日志中,并且不应该写入到响应体中

错误信息

1
2
3
4
5
6
7
8
9
10
{
"errors": [
{
"userMessage": "Sorry, the requested resource does not exist",
"internalMessage": "No car found in the database",
"code": 34,
"moreInfo": "http://127.0.0.1/api/v1/errors/12345"
}
]
}

参考

作者

苏同

发布于

2019-11-07

更新于

2019-11-07

许可协议