API设计的最佳实践
1.对URL使用 kebab-case(短横线分隔方式,小写形式)
比如我们要出一个获取订单列表接口,那么不应该是:
/systemOrders
或 /system_orders
,
而应该是:
system-orders
2.对于url参数的定义,使用小驼峰形式
比如我们要出一个查找特定 ID 商品的接口,那么不应该是
system-orders/{order_id}
或 /system-orders/{OrderId}
,
而应该是:
system-orders/{orderId}
3.单复数形式表明含义
比如我们要出一个获取用户列表的接口,那么不应该是
/User
或 /user
,
而应该是:
/users
4.URL 以集合开始,以标识符结束
如果要保持概念的单一性,一致性。
则不推荐这么定义:
GET /shops/:shopId/category/:categoryId/price
因为这指向的是一个 price 的属性,而不是具体的资源。
推荐这么定义:
GET /shops/:shopId
或 GET /category/:categoryId
5.让动词远离你的资源类 URL
不要在 URL 中使用动词来表示具体要做的事,相反使用对应 HTTP 方法来描述操作。
例如不推荐这样定义:
POST /updateuser/{userId}
,或 GET /getusers
,
而推荐这样定义:
PUT /user/{userId}
6.对非资源类的 URL 使用动词
如果接口只返回一个操作,这种情况下可以使用动词。
例如定义一个接口是向用户重新发送报警:
POST /alarm/100011/resend
7.JSON属性使用小驼峰形式
如果我们需要创建一些 请求体或响应体为 json 的接口,那么json中的属性字段尽量使用 小驼峰表示: 例如不推荐这样写:
{
"user_name": "Bob",
"user_id": 1001
}
而推荐这样写:
{
"userName": "Bob",
"userId": 1001
}
8.监控接口常规定义方法
RESTful HTTP 接口一般会实现 /health,/version,/metrics 等自带方法。
/health
: 用 200 HTTP code 响应请求,表示服务状态可用/version
: 用版本号响应 请求/metrics
: 提供各种指标,如平均响应时间等。- 额外的还有
/debug
,/status
等自带方法等。
9.不要使用 table_name 作为资源名
主要是为了不暴露底层设计,数据表是底层体系结构,不宜暴露对外。
例如数据表是 product_order
那么接口可以设计为:GET /product-orders
10.使用简单序数作为版本
始终对 API 使用版本控制,并将其向左移动,使其具有最大作用域。版本号比如使用 v1,v2等。
例如:
https://api.domain.com/v1/shops/3/products/10
始终在 API 中使用版本控制,因为如果API被外部实体使用,更改端点可能会破坏他们的功能。
11.在响应体中包含总资源数字段
在返回集合时,尽量给一个字段标识可用资源总数。 比如:
{
"users": [
...
],
"total": 1008
}
12.接受 limit 和 offset 参数
在 GET 操作中始终接受 limit 和 offset 参数
GET /shops/offset=5&limit=20
13.获取字段查询参数
返回的字段应该允许用户去选择,以减少接口请求的体积和网络开销,同时对调用方来说不必处理一些不需要的字段。
例如,只需要返回商店的名称,地址和联系方式:
GET /shops/fields=id,name,address,contact
14.不要在URL中通过认证令牌
这是一种不太漂亮的方式,比如:
GET /shops/123?token=123abcABC456789
因为 url 经常会被使用方记录,而 token 也会被记录下,这是没必要的。
我们习惯在 header 头里传递凭证:
Authorization: Bearer xxxxxx, Extra yyyyyy
另外认证令牌应当是有时效性的。
15.验证内容类型
验证 header 头中的 content-type。
注意始终验证内容类型,如果不指定,则默认习惯使用 application/json
类型。
16.对 CURD 函数使用 HTTP 方法
HTTP 方法可以对应“增删改查”操作
- GET:检索查询资源
- POST:创建新的资源和子资源
- PUT:更新现有资源。
- PATCH:更新现有资源,它只更新提供的字段,而不更新其他字段。
- DELETE:删除已存在的资源。
17.在嵌套资源的 URL 中使用关系
以下是一些例子:
GET /shops/2/products
: 从 shop 2 获取产品列表GET /shops/2/products/31
: 从 shop 2 获取产品 31 的详细信息DELETE /shops/2/products/31
: 删除 shop 2 的产品 31PUT /shops/2/products/31
: 更新 shop 2 的产品 31 的信息。注意,只在 resource-URL 上使用 PUT 请求,而非集合上。POST /shops
: 创建一个新 shop,并返回创建的新商店的详细信息。在集合 url 上使用 POST.
18.CORS(跨域资源共享)
一定要为所有面向公共的 API 支持 CORS(跨域资源共享)的header 头 考虑支持 CORS 允许的 “*” 来源,并通过有效的 OAuth 令牌强制授权。 避免将用户凭证与原始验证相结合。
19.安全起见,尽量使用 HTTPS 协议
- 尽量使用HTTPS协议(TLS加密认证),而不是HTTPS协议
- 强制要求所有回调 url,推送通知端点和 webhooks 使用 HTTPS.
20.错误
当客户端发出无效或不正确请求,或向服务传递无效或不正确的数据,而服务拒绝该请求时,就会出现错误。 错误情况包括无效的身份验证凭证,不正确的参数,未知的版本id等等。
- 当由于一个或多个服务错误,而拒绝客户端请求时,一定要返回 4XX 的 HTTP 码
- 考虑处理所有属性,然后在单个响应中返回多个验证结果。
21.黄金法则
- 扁平比嵌套好
- 简单比复杂好
- 字符串比数字好
- 保持一致性比分散去定制要好