 
                在 API 开发或对接中,经常会看到协议中有自定义 code 的设计
- 那为什么要这么设计呢?
- 这种设计有没有什么实践?
- 大厂都是怎么做的呢?
跟随本文,一起揭晓以上问题
为什么还要自定义 code?
HTTP 协议中定义了 5 类 status code
- Informational responses(100–199)
- Successful responses(200–299)
- Redirection messages(300–399)
- Client error responses(400–499)
- Server error responses(500–599)
这其中留给开发者可以用的 status code 少之又少,而实际的业务响应又会有非常多的状态,所以开发者需要一种方式来扩展 code。
这其中最直观的方式就是定义一个标准的响应结构,这个结构中有着一个自定义的 code 字段,它可以用来表示业务的响应状态,如下:
{
    "code":"A1000",
    "message":"会员已过期"
}
所以,自定义 code 本质上是对 status code 的一个扩展,是为了满足实际业务中复杂的状态表达而设计的。
自定义 code 该怎么用?
HTTP 的 status 不够用导致我们设计了自定义 code,但现在很多 API 的 code 都已经被滥用了。
我推荐的做法是:按语义将 HTTP status 当作一级分类,自定义 code 当作二级分类
- 2xx 请求成功
- 4xx 客户端错误,不影响服务可用性
- 5xx 服务端错误,影响服务可用性

2xx 代表成功,实际业务场景下很少会碰到成功之下还要再区分不同的成功状态的,即使遇到了,设计一个更符合业务语义的字段通常也会更好。
所以, 2xx 的响应没必要设置自定义 code

而 4xx、5xx 这种错误响应之下再做错误细分的场景是很常见的,比如 4xx 客户端错误之下需要明确具体的业务错误:支付时用户余额不足、商品库存不足、支付超时等。

现在明确了只为 4xx、5xx 扩展 code,而 code 又是由响应体来承载的,接下来就看看如何设计错误响应体。
错误响应体怎么设计?
先来看看微软在它的 REST API guidlines 里的设计
https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#errorresponse–object
{
  "error": {
    "code": "BadArgument",
    "message": "Multiple errors in ContactInfo data",
    "target": "ContactInfo",
    "details": [
      {
        "code": "NullValue",
        "target": "PhoneNumber",
        "message": "Phone number must not be null"
      },
      {
        "code": "NullValue",
        "target": "LastName",
        "message": "Last name must not be null"
      },
      {
        "code": "MalformedValue",
        "target": "Address",
        "message": "Address is not valid"
      }
    ]
  }
}
GITHUB 在其 REST API 平台上也有示例
{
   "message": "Validation Failed",
   "errors": [
     {
       "resource": "Issue",
       "field": "title",
       "code": "missing_field"
     }
   ]
 }
这里的 code 可以分为以下几类
| Error code name | Description | 
|---|---|
| missing | A resource does not exist. | 
| missing_field | A required field on a resource has not been set. | 
| invalid | The formatting of a field is invalid. Review the documentation for more specific information. | 
| already_exists | Another resource has the same value as this field. This can happen in resources that must have some unique key (such as label names). | 
| unprocessable | The inputs provided were invalid. | 
从 GITHUB 和微软的设计上我们可以得出一些规律
- code 是可读的
- 通常也会包含一个详细描述的 message 字段
- 根据响应,调用方有能力定位到导致错误的资源(字段)