My HTTP API Guidelines

9th February 2022 at 6:59pm

用什么错误码表示业务逻辑上的错误?

这篇 帖子 建议用 409 CONFLICT。简单地说,409 表示 "you've sent the entity at the wrong time",即你的请求体是合法的(因此没有 400 BAD REQUEST),我服务端也是正常运作的(因此没有 5XX 错误),但是此时因为某种外部原因无法处理。

Request ID

在 HTTP 请求的头部带上 X-Request-ID,用来唯一标识一个请求。回包必须将该 X-Request-ID 以 HTTP 头形式原样带回。示例:

X-Request-ID: 921e2b45-83db-4ecd-b17a-2f7a7cf0bd0f

一些调研:

  • GET 请求无法带请求体,所以在请求体中(比如 JSON 结构中)放 request ID 并不合适
  • X-Request-ID 不在 HTTP 规范中,但是相对广泛使用(参考 Wikipedia
  • 有些代理服务器可能会 strip 掉这个头
  • Correlation IDs for microservices architectures 这篇描述了挺长篇幅,应该有有价值的内容,有时间看看

按 ID 批量查询资源

API Handyman 的这篇 文章 给出了一个常见的 URL pattern 设计:

GET /resources?ids=ID1,ID2

其中有几点需要考量:

  1. 用逗号(,)作分隔符是否合适?
  2. 返回体的结构设计
  3. 分页及不存在的 ID 处理

用逗号作分隔符

根据这个 SO 回答,用逗号作分隔符是 OK 的。query component 指 URL 中 ?#(如果没有,则到 URL 末尾)的中间部分,这部分可以包含的字符有

  • a-z, A-Z
  • 0-9
  • / ? : @ ! $ & ' ( ) * + , ; = - . _ ~
  • percent-encoded characters

其中 , / 这些虽然叫作 reserved character,但是这里的 reserved 并不是不能用,而是说如果这些字符如果没有使用它的特殊含义(如作为分隔符),而是当作普通的字符串使用,那么你应该 percent-encode 它。

一些使用了 reserved character 的场景:

  • Google Drive 的文件查看功能:https://drive.google.com/viewerng/viewer?url=http://journals.plos.org/plosone/s/file?id=body.pdf
  • 电商网站中经常会看到 ,
  • 一些 OAuth 的 callback URL

返回体的结构设计

API Handyman 用的方案是:

{
  "ID1": {
    "status": "201",
    "headers": [
      {"header's name": "header's value"}
    ],
    "body": { "the": "response's body"}
  },
  "ID2": {
    "status": "400",
    "headers": [
      {"header's name": "header's value"}
    ],
    "body": { "the": "response's body"}
  }
}

这个结构更适合于创建多个对象时使用,而不适合在查询多个对象时。我觉得应该沿用列表页的回包结构:

{
  "data": {
    "totalCount": 5,
    "content": [
      {
        "id": "498e8220-5342-4277-b1cd-40caecbf9840",
        "name": "main-cluster"
      },
      {
        "id": "498e8220-5342-4277-b1cd-40caecbf9840",
        "name": "second-cluster",
      }
    ]
  },
  "code": 0,
  "message": ""
}