【问题标题】:REST API URI for entities with two different keys具有两个不同键的实体的 REST API URI
【发布时间】:2017-08-18 12:43:57
【问题描述】:

我必须设计一个 API 来管理一个 Document 实体:这个实体的独创性在于它可以有两个不同的 id:

  • id1(数字,即1234)
  • id2(数字,即89)

对于每个文档,只有一个 id 可用(id1 或 id2,不能同时使用)

通常我通过使用查询参数来执行某种“搜索”功能来解决这个问题:

GET /documents?id1=1234
GET /documents?id2=89

但只有在没有子实体的情况下才有效...

假设我想获取文档的作者:

GET /documents/1234/authors

不可能,因为我不知道我得到什么类型的 id:是 id1 还是 id2 ?

GET /documents/authors?id1=1234

我认为不是真正的 REST,因为 id1 然后指的是“作者”实体,而不是“文档”......

GET /id1-documents/1234/authors
GET /id2-documents/1234/authors

然后您创建两个返回相同实体 (/author) 的 URI,但并不真正符合 REST。

GET /documents/id1=1234/authors
GET /documents/id2=89/authors

它看起来像只为 API 创建的复合键,它没有“后端”的含义。对我来说,动态创建“复合”键听起来很奇怪。

GET /document-authors?id1=1234
GET /document-authors?id2=89

在这种情况下,您完全失去了树的概念...您最终会得到一个仅包含根实体的 API。

你看到另一种选择吗? 哪个最好看?

非常感谢。

【问题讨论】:

  • 你能详细说明这两种不同类型的id吗?在您的示例中,它们看起来都像 int,这是否意味着您可以拥有两个不同的文档,其 id 为“89”,但一个文档的 id1 为 89,另一个文档的 id2 为 89?还是 id 在某种程度上是正交/不重叠的?
  • 感谢您的评论。两个ID都是整数,没有限制。但是如果 id1 被定义,则 id2 不是并且互惠的。是的,您可以拥有两个不同的文档,其 id 为“89”,但一个文档的 id1 为 89,另一个文档的 id2 为 89。
  • 魔鬼在细节中。像这样的 URI 看起来和感觉起来简单自然,但是当您需要在过滤实现的字段中的数据中考虑说“/”时,就会变得更加复杂。查询字符串方法在这方面更容易,但看起来不像恕我直言。
  • 抱歉,我不清楚哪个提议最适合您。谢谢

标签: rest api data-modeling


【解决方案1】:

在我看来,您在这里混淆了两种不同的资源 - documentsauthorsdocumentauthor 有关系,但它们应该是单独的资源,因为 authors 存在于任何单独的文档中。考虑到这一点,您需要询问您的客户是否在搜索作者或文档。如果是作者,那么他们应该查询作者 API 而不是文档 API。

例如,对于 id1 89 或 id1 1234 或 id2 4444 文档的所有作者,您可能会这样查询...

GET /authors?docId1=89&docId1=1234&docId2=4444

这应该返回一个作者陈述列表。如果人们自己关心文档,则作者陈述可能包含文档的链接。

或者,如果您正在寻找documents,那么您应该直接查询...

GET /documents?id1=89&id1=1234&id2=4444

您作为子资源建模的内容真的不是子资源。这是 2 个独立资源之间的关系,应建模为一组链接。从documents api 返回的每个文档都应该包含一组authors 链接(如果人们真的关心作者),反之亦然,从作者到文档。

【讨论】:

  • 感谢您的回答。事实上,作者并不是一个真正的子资源,它是一个坏例子。假设 Document 有一个名为“Signatures”或“Metadata”的子资源,那么它就是真正的子资源。我应该如何设计?谢谢
  • 您只需要构建您的 URI,以便两种类型的标识符是不同的,例如/documents/id1Type/89/documents/id2Type/12345。然后每个文档都有一个唯一的 URI,并且子资源位于定义明确的文档 URI (/documents/id1Type/89/signatures) 下。
  • 感谢您的回答。事实上,这可能是一个解决方案:我在 stackoverflow 上多次看到这种可能性。但这不是一个问题 id1Type 不是一个真正的实体,一个真正的对象吗?如果我实现这一点,我将得到两条路线:GET /documents/id2Type/{id}/signatures 和 GET /documents/id1Type/{id}/signatures。 2 个 URI 返回相同的资源,不是吗?再次感谢
  • 根据您对 id 类型的描述,任何文档只能有一个 id,这是 2 种 id 类型之一,但 id 重叠,因此您需要一种方法来区分它们。通过在路径中命名 id 类型,如果该 id 存在,则允许返回文档,否则为 404 - 因此 URI 语义是安全的。搜索应该转到顶级 /documents 资源,这样就不会有问题。
  • 另外,名义上/documents/idtype1 可以是一个资源——它可以返回该id类型的所有文档,也可以用于创建该id类型的文档。资源与实体不同。
【解决方案2】:

这是一个来自 SlashDB 的固执己见的解决方案,它允许记录过滤和同时遍历相关资源。

该示例与您的示例类似 - 两个实体 Artist 和 Album。

让我们首先确定艺术家。

艺术家 ID:

https://demo.slashdb.com/db/Chinook/Artist/ArtistId/2

艺术家姓名:

https://demo.slashdb.com/db/Chinook/Artist/Name/Accept

艺术家可能已发行专辑。这两个实体是相关的。我们允许使用相关实体的名称扩展 URL,如下所示:

https://demo.slashdb.com/db/Chinook/Artist/Name/Accept/Album

你可以继续“前进”,比如从那些专辑中找到曲目

https://demo.slashdb.com/db/Chinook/Artist/Name/Accept/Album/Track

甚至继续过滤,即只过滤小于 300000 毫秒的轨道:

https://demo.slashdb.com/db/Chinook/Artist/Name/Accept/Album/Track/Milliseconds/..300000

【讨论】:

  • 感谢您的回答。它看起来真的很像@sisyphus 解决方案,所以我想如果许多消息来源都同意这个解决方案,那肯定很有趣;)
猜你喜欢
  • 1970-01-01
  • 2013-03-03
  • 2023-03-14
  • 2011-11-24
  • 1970-01-01
  • 2012-06-09
  • 2018-12-27
  • 2013-02-26
  • 1970-01-01
相关资源
最近更新 更多