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/:shopIdGET /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 等自带方法。

  1. /health: 用 200 HTTP code 响应请求,表示服务状态可用
  2. /version: 用版本号响应 请求
  3. /metrics: 提供各种指标,如平均响应时间等。
  4. 额外的还有 /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 方法可以对应“增删改查”操作

  1. GET:检索查询资源
  2. POST:创建新的资源和子资源
  3. PUT:更新现有资源。
  4. PATCH:更新现有资源,它只更新提供的字段,而不更新其他字段。
  5. DELETE:删除已存在的资源。
17.在嵌套资源的 URL 中使用关系

以下是一些例子:

  1. GET /shops/2/products: 从 shop 2 获取产品列表
  2. GET /shops/2/products/31: 从 shop 2 获取产品 31 的详细信息
  3. DELETE /shops/2/products/31: 删除 shop 2 的产品 31
  4. PUT /shops/2/products/31: 更新 shop 2 的产品 31 的信息。注意,只在 resource-URL 上使用 PUT 请求,而非集合上。
  5. POST /shops: 创建一个新 shop,并返回创建的新商店的详细信息。在集合 url 上使用 POST.
18.CORS(跨域资源共享)

一定要为所有面向公共的 API 支持 CORS(跨域资源共享)的header 头 考虑支持 CORS 允许的 “*” 来源,并通过有效的 OAuth 令牌强制授权。 避免将用户凭证与原始验证相结合。

19.安全起见,尽量使用 HTTPS 协议
  1. 尽量使用HTTPS协议(TLS加密认证),而不是HTTPS协议
  2. 强制要求所有回调 url,推送通知端点和 webhooks 使用 HTTPS.
20.错误

当客户端发出无效或不正确请求,或向服务传递无效或不正确的数据,而服务拒绝该请求时,就会出现错误。 错误情况包括无效的身份验证凭证,不正确的参数,未知的版本id等等。

  1. 当由于一个或多个服务错误,而拒绝客户端请求时,一定要返回 4XX 的 HTTP 码
  2. 考虑处理所有属性,然后在单个响应中返回多个验证结果。
21.黄金法则
  1. 扁平比嵌套好
  2. 简单比复杂好
  3. 字符串比数字好
  4. 保持一致性比分散去定制要好