如何设计资源标识符?


如何设计 RPC 接口 中讲到一个观点:

资源在用户侧以 hyper media 存在;资源流到服务中以对象来组织;资源落到存储里就变成了id + content。索引 content 的 id,一般又以 单个集合 的形态存在,具体到数据库中,id 以 聚簇索引存在,content 以聚簇索引叶节点存在

越来越多的产品按照先获取 id 再读取 content 来访问资源

在REST论文中也有类似的描述:

REST 对于信息的核心抽象是资源。任何能够被命名的信息都能够作为一个资源。资源 R 是一个随时间变化的成员函数 MR(t),该函数将时间 t 映射到等价的一个实体或值的集合,集合中的值可能是资源的表述 和/或 资源的标识符

Data=ID+Content

其中包含了以下层面的意思:

  1. 服务是围绕资源建立的,服务存在的价值是对资源更新和组织
  2. 每种资源必须依靠 id 标志,内容本身只是为了最终呈现,作为资源的识别, id 才至关重要
  3. ID 又以 单个集合 形态存在,“集合” 是一种特殊的资源,包含相同类型的子资源列表

一般的应用中,通常使用资源唯一 ID 标识资源。ID 生成一般依赖数据库递增,或者 分布式ID生成服务。但在大型系统中,一般有很多资源,在使用资源ID标识资源时,通常需要使用特定于资源的元组来标识资源,例如:<群ID、消息ID> 或<公众号ID,消息ID,文章位置>。这会带来以下问题:

  • 使用者必须记忆匿名元组、顺序
  • 元组通常难以传递
  • 通用服务不理解专用的元组
  • 专用元组限制了 API 设计的灵活性

针对以上问题,一般来说可以将元组利用一定的机制进行拼接组装,生成一个唯一的ID。最常见的例子是微信公众平台的OpenID:

OpenID = WechatID (用户微信号) & APPID (公众平台ID)(两个数据加密得到的字符串)

然而特定的拼接方式仍然没有解决理解、通用性问题

理解和通用性问题,其实有比较通用的解决方案。既以名称-值 对的形式,建立自描述(self-descriptive)的标识符。语言描述可能比较难以理解,那么还是以微信公众平台OpenID为例,如果标志符以下面形式组织将会更容易理解:

wechatid=XXX&appid=XXX(加密得到的字符串)

但是以上组织方式引入了一个新的问题,到底该把哪些数据作为生成标识符的一部分呢?答案就是:集合(依据就是开头的片段)。资源可以由 集合 ID资源 ID 组成;如果资源包含子资源,则子资源可以由 父资源 后跟 子资源的 ID

示例 1:存储服务具有一组 buckets,其中每个存储分区都有一组 objects

API 服务名称 集合 ID 资源 ID 集合 ID 资源 ID
//storage.googleapis.com /buckets /bucket-id /objects /object-id

示例 2:电子邮件服务具有一组 users。每个用户都有一个 settings 子资源,而 settings 子资源拥有包括 customFrom 在内的许多其他子资源:

API 服务名称 集合 ID 资源 ID 资源 ID 资源 ID
//mail.googleapis.com /users /name@example.com /settings /customFrom

本文作者:cyningsun
本文地址https://www.cyningsun.com/08-09-2020/resouce-id-design.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!

# API Design