REST 样式 URL 中的 ID 值



如果我的应用程序有多种方法来标识资源,例如全局唯一标识符,以及更人性化值的复合键,哪个被认为是可取的?

举个例子:

  • https://localhost:12345/api/customer/{customerId:int}/product/{productSku}
  • https://localhost:12345/api/customer/732/product/46
  • https://localhost:12345/api/customer/abc-spares-ltd/product/CF31-APB

而不是:

  • https://localhost:12345/api/product/{productGlobalId:Guid}
  • https://localhost:12345/api/product/B51B6E8A-B68E-4FD0-9FC2-BAA682FAFB14

这是一种可能性,但似乎毫无意义:

  • https://localhost:12345/api/customer/{customerId:int}/product/{productGlobalId:Guid}
  • https://localhost:12345/api/customer/81C51258-DDDD-4815-A207-37ED735D1AEA/product/B51B6E8A-B68E-4FD0-9FC2-BAA682FAFB14

除了在这种情况下一个不太易读(更直接的整数很容易成为系统中的唯一整数)之外,选择背后的原因是什么?应该同时实现两者,还是应该只有一个给定资源的 URL?

我认为有些事情与此有关:

  • 第二个选项将需要较少的"友好"ID 值和内部全局唯一值之间的转换。
  • 在 SQL 数据库中,使用主键意味着不必定义进一步的索引(这些索引在插入/更新时会命中)。
  • 在NoSQL数据库中,"get-by-ID"是典型的,如果不使用数据库系统的"主键"等效项,或者可能需要一些转换,查询甚至可能返回最终一致的数据。
  • 这两件事之间是否存在关系(在此示例中有,但由于存在 guid ID,因此并非绝对有必要将产品作为集的子集查找。
  • DDD 样式的聚合设计是否会为决策提供信息?例如,产品不会成为客户聚合的一部分,即使实际上存在关系(例如,一个客户不会"看到"另一个客户的产品)。
  • 如果理论上可以修改产品的"SKU",那么 URL 实际上可能最终指向不同的资源。使用不可变的"内部"标识符,这是不可能的(您可能会通过软删除实现为 404,并创建一个全新的产品)。

REST不关心你对URI使用什么拼写。

RESTAPI(HTTP)的目的是让你的域名像网站一样工作。 因此,当你考虑资源时,你应该考虑你的表示从外部意味着什么,而不是从内部看如何(即,不是你当前的实现)。

也就是说,您应该能够在使用 RDBMS 和 no-sql 文档存储之间切换,而无需更改 API。 您的 API 公开集成资源,以便客户端不受您的实施选择的影响。 Jim Webber的RESTful Systems的领域驱动设计扩展了这一点。

除了在这种情况下一个不太易读(更直接的整数很容易成为系统中的唯一整数)之外,选择背后的原因是什么?

您应该选择与 RFC 3986 一致的拼写(路径中的层次结构、查询字符串中的非分层元素、主资源中包含的辅助资源的片段)。

酷 URI 不要改变 - 您使用的拼写应该通过保持 URI 随着时间的推移保持稳定(包括将它们与可能随时间演变的实现分离)来激励。

你应该选择人类可读的拼写——机器消费者并不关心,因为他们只是点击链接或填写模板(假设你的API包含超媒体功能)。

示例:您为哪个添加了书签? 谷歌,还是 216.58.209.164 ?

应该同时实现两者,还是应该只有一个给定资源的 URL?

每个资源总是会有一个 URI - 这有点融入定义。 也就是说,您可能有许多资源在任何给定时刻共享相同的表示形式。

菲尔丁在他的论文中使用了这个例子。

例如,学术论文的">

作者首选版本"是其价值随时间变化的映射,而与"在会议X论文集上发表的论文"的映射是静态的。这是两个不同的资源,即使它们在某个时间点都映射到相同的值。这种区别是必要的,以便可以独立识别和引用这两种资源。软件工程的一个类似示例是在引用"最新版本"、"修订版号 1.2.7"或"橙色版本中包含的修订版"时单独标识版本控制的源代码文件。

看看你的其他想法...

DDD 样式的聚合设计是否会为决策提供信息?例如,产品不会成为客户聚合的一部分,即使实际上存在关系(例如,一个客户不会"看到"另一个客户的产品)。

不是真的,因为事情比这更复杂。 如上所述,集成源不是域模型中的实体(请参阅上面链接的Webber谈话)。 此外,将持久化的数据对齐到"聚合"中是一个随时间变化的实现细节。

请注意,您通常只会运行最新的域模型,但您的集成应向后兼容以支持较旧的客户端。

菲尔丁

REST 适用于跨多个组织的基于网络的长期应用程序。

最新更新