在 REST 中,主数据表示被称为资源。实践证明,描述全面而与资源内容一致的 REST 命名,是我们设计良好的 RESTful API 的最佳方式。
在 REST 中,关键信息可以抽象为一种资源。任何能被命名的信息都可以是资源:文档或图片、临时服务(例如“广州今日天气”)、其他资源的集合、非虚拟对象(例如人)等等。换句话说,任何可能被我们超文本引用的目标的概念都必须符合上述资源的定义。资源是对一组实体的概念映射,而不针对恰当时间点的实体。 ------ 来源罗伊菲尔丁
资源可以是单例或者集合。例如,在银行业务中, “ customers
” 是集合资源,“ customer
”是单例资源。我们可以用 URI “ /customers
” 来访问 customers
这个集合资源,也可以用 URI “ /customers/{customerId}
” 识别单个customer
资源。
一个资源也可以包含子集合资源。例如,在银行业务中,特定用户 “ customer
” 的子集合资源 accounts
可以使用 URN “ /customers/{customerId}/accounts
“ 进行标识。同样的道理, “ account
“ 子集合资源中的单个资源“ account
”可以通过以下方式进行标识:“ /customers/{customerId}/accounts/{accountId}
”。
REST API 使用统一资源标识符(URI)来定位资源。在设计 REST API 时,我们应该创建能够向 API 的潜在用户传达 资源模型的 URI。如果资源的命名良好,API 会直观易用。反之,API 可能会令人难以使用和理解。
REST 约束中,统一接口约束可以通过 URI 和 HTTP 动词组合来解决,请根据对应标准和约定组合使用。
以下是我们创建 API 资源时有关 URI 命名的小 tips:
REST 资源命名最佳实践
使用名词来表示资源
RESTful URI 应该指事物,因此用(名词)来代表资源,而不是动作(动词)。除此之外,名词有动词不具有的属性,也就是说,资源也是有属性的。以下是一些资源示例:
- 系统用户
- 用户帐户
- 网络设备等
对应的资源 URI 可以设计如下:
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/
http://api.example.com/user-management/users/{id}
为了更清楚,我们可以把资源原型划分为四个类别(文档,集合,存储和控制器),我们鼓励将资源放入一个模型,并始终保持相同的命名约定。 为了统一性,建议同一资源设计多个混合路径。
1、文档
文档资源是类似于对象实例或数据库记录的单一概念。在 REST 中,我们可以把文档资源视为资源集合中的单个资源。文档的状态表示通常包括具有值的字段和指向其他相关资源的链接。
以下是使用“单数”名称表示文档资源原型示例:
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/{id}
http://api.example.com/user-management/users/admin
2、集合
集合资源从属于服务端一方,由服务端管理相应的资源目录。客户端可以申请将新资源添加到集合中,由集合资源决定是否为此创建新资源。集合资源不仅决定自身包含的内容,也决定包含的每个资源的 URI 。
以下是使用“复数”名称表示集合资源的原型示例:
http://api.example.com/device-management/managed-devices
http://api.example.com/user-management/users
http://api.example.com/user-management/users/{id}/accounts
3、存储
存储从属于客户端一方,由服务端管理相应的资源库。存储资源允许 API 客户端放入资源、存取资源、删除资源。存储不会生成新的 URI。相反,每个存储的资源都有一个客户端在最初放入存储时选择的 URI 。
以下是使用“复数”名称表示存储资源原型示例:
http://api.example.com/cart-management/users/{id}/carts
http://api.example.com/song-management/users/{id}/playlists
4、控制器
控制器资源模拟了一个过程概念。控制器资源就像可执行函数,具有参数和返回值,输入和输出。
以下是使用“动词”表示控制器原型的示例:
http://api.example.com/cart-management/users/{id}/cart/checkout
http://api.example.com/song-management/users/{id}/playlist/play
关键:一致性
使用一致的资源命名约定 URI 格式,就可以达到对资源内容最小化、最大可读性和可维护性的目的。下面是一些设计命名时的 Tips:
1、使用正斜杠(/)表示层次关系
正斜杠(/)字符用于 URI 的路径部分,以指示资源之间的层次关系。例如
http://api.example.com/device-management
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices/{id}
http://api.example.com/device-management/managed-devices/{id}/scripts
http://api.example.com/device-management/managed-devices/{id}/scripts/{id}
2、避免在 URI 中使用尾部正斜杠(/)
URI 尾部正斜杠(/)不添加语义值,没有含义,还会导致人们混淆,请避免这种情况。
http://api.example.com/device-management/managed-devices/ /避免/
http://api.example.com/device-management/managed-devices /推荐/
3、使用连字符( - )来提高 URI 的可读性
为了让 URI 易于扫描和理解,建议使用连字符( - )来提高长路径段中名称的可读性。示例如下:
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location //推荐
http://api.example.com/inventory-management/managedEntities/{id}/installScriptLocation //避免
4、不要使用下划线(_)
使用下划线代替连字符作为分隔符也是可行的,但在某些应用程序的支持字体中,下划线(_)会让浏览器或显示器区分不清或隐藏。
为避免这种混淆,请使用连字符( - )代替下划线(_),示例如下:
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location //易读
http://api.example.com/inventory_management/managed_entities/{id}/install_script_location //不易读
5、在 URI 中使用小写字母
URI 路径应首选小写字母,例如:
http://api.example.org/my-folder/my-doc //1
HTTP://API.EXAMPLE.ORG/my-folder/my-doc //2
http://api.example.org/My-Folder/my-doc //3
在上面的例子中,1 和 2 指向相同,而 3 不同,因为 3 在路径中使用了大写字母 My-Folder。
6、不要使用文件扩展名
文件扩展名不仅可阅读性差,这种做法也带不来什么好处:相反,删掉他们还可以减少 URI 的长度,因此就更没理由这样用了。
除此之外,如果是想通过文件扩展名突出显示这个 API 的媒体类型,建议通过Content-Type
来确定如何处理主题内容,示例如下:
http://api.example.com/device-management/managed-devices.xml /避免使用/
http://api.example.com/device-management/managed-devices /正确示例/
不要在 URI 中使用 CRUD 功能名称
请不要用 URI 来指示 CRUD 功能,URI 应该仅仅用于标识唯一资源,除此之外并无其它。需要的话,我们应该使用 HTTP 请求方法来指示执行哪个 CRUD 功能。
HTTP GET http://api.example.com/device-management/managed-devices //获取所有设备
HTTP POST http://api.example.com/device-management/managed-devices //创建新设备
HTTP GET http://api.example.com/device-management/managed-devices/{id} //通过 ID 获取相应设备
HTTP PUT http://api.example.com/device-management/managed-devices/{id} //通过 ID 更新相应设备
HTTP DELETE http://api.example.com/device-management/managed-devices/{id} //通过 ID 删除相应设备
使用查询组件过滤 URI 集合
有时我们需要根据某些特定资源属性对资源进行排序、过滤或限制。这种情况下建议不要创建新的 API ,而是在对应的资源 API 中启用排序,过滤和分页功能,将输入的参数作为查询条件传递。例如
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices?region=USA
http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ
http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ&sort=installation-date
知识扩展:
了解更多 REST API 相关知识。