分享一些优雅的API接口开发规范

原创
03/03 15:05
阅读数 873

前言

优雅的API接口会让前端后端在对接过程中达成一些默契,提供一些愉悦的开发体验,对API接口的质量提升也有很大的一些帮助,本文罗列一些我们团队在日常开发过程中达成的一些共识,可能部分只适合我们自己的团队,也可能部分不太符合国际标准,只是做一些分享,并不代表本文提及的设计和共识都是主流,也不代表本文未提及的部分都很拉垮。

我们的接口普遍采用了 POST JSON 方式,没有使用 restful 风格的接口规范:

> 我早前写过一篇文章《与其不标准的rest,不如POST一把梭》,大意是说,rest风格的接口的请求方法和访问资源一般很难界定,处理这些边界问题往往需要大量的思考,而且结果还不一定非常符合标准。

接口命名约定

  • 清晰的API作用域

    后端使用 Controller 层将相同作用域的接口放到一起,比如 /api/user/*** 即代表了 与用户相关 的部分接口,其他与用户不相关的部分接口不允许放到 /user/ 下。

  • 动宾语法的接口名称

    使用 动词+形容词+资源名称 的方式来定义一个接口,如 get UserInfo update OrderStatus add My Orderdelete All Log 做到看接口地址即清楚接口实现的功能

字段命名和数据类型约定

  • 字明其意的字段名称

    • 使用 List 结尾表示传输的数据是数组,避免纠结名词的单复数形式是什么:
    {
        roleList: [] // 角色数组
    }
    
    • 使用 Info 结尾表示传输的数据是对象,前面的词表示对象的类型:
    {
        roleInfo: {} // 角色对象
    }    
    
    • 使用 Id 结尾表示传输的数据可能是另一个对象的主键ID:
    {
        nickname: "Hamm",
        roleId: 1 // 该用户有一个角色,ID为1
    }    
    
    • 使用 Code 结尾表示传输的数据可能是一个全局唯一的编码(可以输入,如不输入将自动生成):
    {
        id: 1,
        materialCode: "P20220123214" //  自动生成或手动输入,但一定全局唯一的编码
    }    
    
    • 使用 Time 结尾表示传输的数据可能是一个服务器所在时区的毫秒时间戳(依赖服务器时区,适合 L10n 项目,稍加改造即可支持 I18n):
    {
        id: 1,
        createTime: 1692757563000 //  创建时间, 可自行按产品需求转换显示的时间
        // 比如 😄一炷香之前
    }    
    
    • 使用parentId, children 表示树结构的父节点ID和子树列表:
    {
        id: 1091,
        parentId: 1,
        children:[
            {...}
        ]
    }
    

    还有很多,罗列不完了。

  • 正确的数据格式返回

    • 承诺是数组类型返回的数据,无数据时不允许返回 null 必须返回 []
    • 承诺是布尔类型返回的数据,仅允许返回 true false null,不允许返回 1,0 等数字类型,不允许返回 "true" "false", "null" 等其他任何值
    • 承诺是数字类型的返回数据,仅允许返回 数字null 不允许返回其他任何数据
    • 承诺返回的字段,即使没有任何值,对象中的属性必须存在且为 null, 不允许没有值的时候不返回字段
    • 承诺是时间戳类型的返回数据,只允许返回 数字,不允许返回 null
    • 承诺是字符串类型返回的数据,只允许返回 字符串,不允许返回 null
    • 承诺是百分比的返回数据,只允许返回对应的 小数 且不需要 X100

必要字段约定

所有的 数据库存储 数据必须包含一下字段:

  • ID 主键ID

    表示主键ID,数字类型,所有CURD接口的索引字段(某些场景下的 code 也可以作为索引字段)

  • createTime 首次创建时间

    首次创建的时间,毫秒时间戳,可作为排序使用,一旦创建不允许修改

  • updateTime 最后修改时间

    最后修改的时间,毫秒时间戳,可作为排序使用,不允许手动修改,系统自动更新

明确的异常提示

任何服务端出现的异常,包括但不限于 服务端BUG 前端传参验证问题 服务侧网络问题 第三方依赖问题 ,所有环境都应抛出文案优化后的具体错误信息,不允许直接全局抛出 请求错误 这种不明确错误内容的错误信息,否则无法高效的排除错误。 生产环境 未及时捕获的异常应返回文案优化后的模糊错误提醒, 如 “操作出现异常,请稍后再试或联系客服”,且应及时分析对应的错误信息,捕获并处理异常后优化文案返回具体的错误信息。

所有的异常返回不允许返回一些敏感信息,如数据库连接地址、账号密码等。

明确返回的标准JSON结构

整个http返回状态码固定为200,其中返回的body数据为 JSON 且标准返回如下:

{
    "code": 200,
    "message": "获取成功",
    "data": ... // data为可选
}

其中, code为状态码,为整数数字类型,尊重以下规则:

  • 200 为操作成功,表示客户端后续无必要操作
  • 201 为操作成功,但后续还有必要操作
  • 401 为需要跳转到登录页面
  • 503 为繁忙表示,表示本次请求没有成功,但前端可能需要重新发起请求
  • 404 查询的数据不存在,前端可能需要打开新增页面
  • 405 请求没有使用POST请求
  • 415 请求没有使用JSON交互
  • 501 不存在的请求接口,需要确认请求API地址是否正确
  • 50x 其他服务端提示的错误信息
  • 其他状态码,参考具体的业务逻辑

任何阶段的接口高可用

如后端使用编译型语言开发,经常会碰到修复完一个BUG之后提交到开发服务器部署,导致发布重启阶段接口不可用,我们要求:

> 在任何阶段(开发、测试、生产)都必须提供备用服务进行负载,尽可能保证任何情况下服务端 http 状态码的返回均是 200

标准的接口文档和版本管理

接口文档需要满足以下一些规则:

  • 标准的文档格式,必须提供 url 参数 响应结构
  • 提供枚举类型,必须提供枚举可选项的 枚举值 枚举显示值
  • 提供必填字段、必填场景以及校验规则
  • 所有文档的变更必须提供变更记录和说明

That's all

今天的分享就到这里,下一篇我们继续。

欢迎在评论区分享你们的一些规范或者设计方式,大家互相学习和讨论。

我们最近在使用 vue3 TypeScript ElementPlus Java SpringBoot JPA 等技术栈实现一套基于面向对象的前后端统一开发全栈项目,欢迎关注:

前端:https://github.com/HammCn/AirPower4T

后端:https://github.com/HammCn/AirPower4J

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部