API设计的几条原则( 二 )


产生这类问题的根源还是缺乏合理的抽象 。如果存在 API 中可以通过用户组操作用户,通过用户的 URI 操作用户属于的用户组,这其中的问题是缺少了成员这一概念 。用户组下面的本质上并不是用户,而是用户和用户组的关系,即成员 。
版本化一个对外开放的服务,极大的概率会发生变化 。业务变化可能修改 API 参数或响应数据结构,以及资源之间的关系 。一般来说,字段的增加不会影响旧的客户端运行 。但是当存在一些破坏性修改时,就需要使用新的版本将数据导向到新的资源地址 。
版本信息的传输,可以通过下面几种方式

  • URI 前缀
  • Header
  • Query
比较推荐的做法是使用 URI 前缀,例如/v1/users/表达获取 v1 版本下的用户列表 。
常见的反模式是通过增加 URI 后缀来实现的,例如/users/1/updateV2 。这样做的缺陷是版本信息侵入到业务逻辑中,对路由的统一管理带来不便 。
使用 Header 和 Query 发送版本信息则较为相似,不同之处在于,使用 URI 前缀在 MVC 框架中实现相对简单,只需要定义好路由即可 。使用 Header 和 Query 还需要编写额外的拦截器 。
合理命名设计 API 时候的命名涉及多个地方:URI、请求参数、响应数据等 。通常来说最主要,也是最难的一个是全局命名统一 。
其次,命名需要注意这些:
  • 尽可能和领域名词保持一致,例如聚合根、实体、事件等
  • RESTful 设计的 URI 中使用名词复数
  • 尽可能不要过度简写,例如将 user 简写成usr
  • 尽可能使用不需要编码的字符
【API设计的几条原则】用领域名词来对 API 设计命名不是一件特别难的事情 。识别出的领域名词可以直接作为 URI 来使用 。如果存在多个单词的连接可以使用中横线,例如/orders/1/order-items
安全安全是任何一项软件设计都必须要考虑的事情,对于 API 设计来说,暴露给内部系统的 API 和开放给外部系统的 API 略有不同 。
API设计的几条原则

文章插图
 
内部系统,更多的是考虑是否足够健壮 。对接收的数据有足够的验证,并给出错误信息,而不是什么信息都接收,然后内部业务逻辑应该边界值的影响变得莫名其妙 。
而对于外部系统的 API 则有更多的挑战 。
  • 错误的调用方式
  • 接口滥用
  • 浏览器消费 API 时因安全漏洞导致的非法访问
所以设计 API 时应该考虑响应的应对措施 。针对错误的调用方式,API 不应该进入业务处理流程,及时给出错误信息;对于接口滥用的情况,需要做一些限速的方案;对于一些浏览器消费者的问题,可以在让 API 返回一些安全增强头部,例如:X-XSS-Protection、Content-Security-Policy 等 。
API 设计评审清单
  • URI 命名是否通过聚合根和实体统一
  • URI 命名是否采用名词复数和连接线
  • URI 命名是否都是单词小写
  • URI 是否暴露了不必要的信息,例如/cgi-bin
  • URI 规则是否统一
  • 资源提供的能力是否彼此独立
  • URI 是否存在需要编码的字符
  • 请求和返回的参数是否不多不少
  • 资源的 ID 参数是否通过 PATH 参数传递
  • 认证和授权信息是否暴露到 query 参数中
  • 参数是否使用奇怪的缩写
  • 参数和响应数据中的字段命名统一
  • 是否存在无意义的对象包装 例如{"data":{}'}
  • 出错时是否破坏约定的数据结构
  • 是否使用合适的状态码
  • 是否使用合适的媒体类型
  • 响应数据的单复是否和数据内容一致
  • 响应头中是否有缓存信息
  • 是否进行了版本管理
  • 版本信息是否作为 URI 的前缀存在
  • 是否提供 API 服务期限
  • 是否提供了 API 返回所有 API 的索引
  • 是否进行了认证和授权
  • 是否采用 HTTPS
  • 是否检查了非法参数
  • 是否增加安全性的头部
  • 是否有限流策略
  • 是否支持 CORS
  • 响应中的时间格式是否采用ISO 8601标准
  • 是否存在越权访问
更多精彩洞见,请关注微信公众号:ThoughtWorks洞见
文/ThoughtWorks少个分号




推荐阅读