11

我在概念上很难理解有关版本化资源的 URL 的正确内容。

假设我有一个应用程序,它以非常类似于版本控制系统的方式跟踪食谱,比如像 RCS 之类的老派。每个版本都可以是一段时间的工作副本,然后从中创建一个新版本。每个版本都有与之关联的评论,并且不共享评论。我可以随时回顾历史并查看配方的演变过程,但每个实例始终被视为同一配方的一个版本。我试图找出构建 URL 以引用这些的最合适的方法,但我无法理解子资源和时间资源等之间的一些差异。

我见过的两种主要方法是:

> 1) query parameters
> -- /recipes/ultimate-thing                -> List of available versions of Ultimate Thing
> -- /recipes/ultimate-thing?version=2      -> Version 2 of Ultimate Thing
> -- /recipes/ultimate-thing?version=latest -> Current working version of Ultimate Thing

2a) Nested resources with versions considered subresources
-- /recipes/ultimate-thing/versions/      -> List of available versions of Ultimate Thing
-- /recipes/ultimate-thing/versions/2     -> Version 2 of Ultimate Thing
-- /recipes/ultimate-thing                -> Current working version of Ultimate Thing

2b) Nested resources with the list at the resource
-- /recipes/ultimate-thing                 -> List of available versions of Ultimate Thing
-- /recipes/ultimate-thing/versions/2      -> Version 2 of Ultimate Thing
-- /recipes/ultimate-thing/versions/latest -> Current working version of Ultimate Thing

我觉得每次我试图说服自己采用一种方法时,我都觉得我缺乏理解来为该方法构建适当的理由。

1 似乎是很多 Rails 人的首选,但我不确定如何明确何时要创建新版本的配方,因为 POST 到特定资源(/recipes/ultimate-thing)通常想要创建具有该名称的资源,如果它不存在,是否适合返回类似 404 的内容而不是创建它,并且只发布到/recipes以创建新的食谱,然后允许 POST 到/recipes/ultimate -创建新版本的东西?另外,如何表示评论?如果没有版本,我可以做类似/recipes/ultimate-thing/comments 的事情,但是/recipes/utlimate-thing/comments?version=latest看起来很丑,而 2b 确实看起来更明确“最新版本的终极事物配方的评论”,2a 似乎最干净。

事实上,我通常最喜欢 2a,但我很难确定版本是食谱的子资源,因为没有食谱,一个版本食谱,但该食谱的所有版本都应该在逻辑上组合在一起。

我还在 stackoverflow 上看到了 2b,但它似乎过于冗长,因为您一直需要/recipes/ultimate-thing/version/latest/comments之类的东西。虽然如果我认为一个版本是一组带有可以注释的说明的成分,而一个食谱是一个具有相似意图的版本的集合,那么这确实是最有意义的。

我真的很喜欢 2a,但是我所缺少的方法是否有一些东西使它成为一个坏主意?我是否遗漏了 1 如何工作的东西,这使得很多人似乎更喜欢它?

或者总是做类似/recipes/ultimate-thing/latest/recipes/ultimate-thing/2/comments 之类的事情是否更有意义,即使这使得这些是同一食谱的不同修订版最不明确?

我不确定这是否是一个非常合适的论坛,我只是想讨论一下,所以我明白为什么一种方法会比另一种更好。

4

4 回答 4

9

哇。好问题。我也发现 REST 的最大挑战之一是它是一种风格,而不是严格的规范。这种风格似乎没有被很好地理解,也没有任何东西可以强制它。

简短回答:风格#1:/recipes/cake?version=2

这种风格似乎最适合我。只是在快速谷歌搜索之后,我发现查询参数被认为是 URI 的一部分。因此,在 URI 中放置一个标识属性似乎是合适的。

样式 2 和 3 似乎违反了路径段表示 ID 和子资源的其他 REST 约定。因此,样式/recipes/cake/2看起来像 ID 为 2 的“蛋糕”资源。/recipes/cake/version/2使“版本”看起来是子资源,而实际上它是父资源的属性资源。

于 2013-02-27T22:28:36.720 回答
4

我去年年底刚刚实现了这种模式,并结合了 2a 和 2b:

2c) Nested resources with versions considered subsets
-- /recipes/ultimate-thing/versions/      -> List of available versions of Ultimate Thing
-- /recipes/ultimate-thing/versions/2     -> Version 2 of Ultimate Thing
-- /recipes/ultimate-thing/versions/latest-> Redirect to current working version of Ultimate Thing

不要将较长的 URI 视为“子资源”或“属性”,就像 URI 标识事物一样将 URI 视为标识数据更为自然,而且,由于 HTTP URI 是分层的,较长的 URI 指的是数据的子集。集合中的项目是数据:集合中所有数据的子集。“事物”的“属性”是数据:关于该事物的所有数据的子集。“子资源”是关于“事物”的数据,它不独立于其父级而存在,因此是有关父级的所有数据的子集。

在你的情况下,你不必做太多的心理柔道来思考recipes/cherry-pie/关于樱桃派是什么以及如何制作的所有数据,而不是特定版本的说明。这包括身份信息和其他非特定于版本的数据,还包括指向 的链接versions/,以及指向历史和有趣视频的链接,在这些视频中有人会遇到一个人。然后,URIrecipes/cherry-pie/versions/是所有版本化的樱桃派数据的子集;一般来说,它只不过是表单中每个 URI 的链接集合recipes/cherry-pie/versions/{version}/。我还将包含在versions/文档链接中recipes/cherry-pie/versions/latest/,该链接会临时重定向到recipes/cherry-pie/versions/182/最新版本或任何最新版本。

这对客户来说非常自然。许多人在他们认为资源爆炸的情况下绊倒,并认为可怜的客户可能跟不上。但是,如果您按照自然用户工作流边界划分资源,则不会有问题。一些客户会想要浏览一组食谱;有些会深入到单个配方(无论版本如何);有些人会向下钻取,想知道有多少个版本,哪个是最新的,并从中进行选择;有些会向下钻取并检索单个版本。如果您想显示单个配方或所有配方的所有版本,您可能做错了什么(在极少数情况下您不是,请设计另一个资源,例如recipes/byname/pie/quickview,它收集所有数据并大量缓存它)。

于 2013-02-28T16:30:08.677 回答
1

这完全取决于您如何查看资源版本。这些是否仅用于 wiki 中的历史跟踪,或者版本是单独的资源。在第一种情况下,EJK 答案似乎是一个很好的解决方案。对于第二种情况,为资源版本/变体创建新的唯一标识符可能是另一种解决方案。例如:

3) Resources with versions
-- /recipes/                          -> List of available recipes versions
-- /recipes/ultimate-thing-version-2  -> Version 2 of Ultimate Thing
-- /recipes/ultimate-thing            -> The "offical" version of Ultimate Thing

如果资源是彼此的变体,这甚至是更优选的解决方案:

3) List of recipes
-- /recipes/                           -> List of available recipes and variations
-- /recipes/ultimate-thing-with-sugar  -> The Ultimate Thing recipe with sugar
-- /recipes/ultimate-thing-with-honey  -> The Ultimate Thing recipe with honey
于 2015-10-17T17:47:39.163 回答
0

我有一个用例,其中每个版本的创建时间至关重要。API 必须回答的常见问题是:

  1. 最新版本是/recipes/ultimate-thing什么?
  2. /recipes/ultimate-thing2019-01-01 的最新版本是什么?
  3. /recipes/ultimate-thing在 2019-01-01 和 2019-01-31 之间创建了哪些版本?

数字 3. 在我看来是查询参数的一个明显案例:

-- /recipes/ultimate-thing?versions_since=2019-01-01&versions_until=2019-01-31

对 2. 使用相同的方法可能不会有什么坏处:

-- /recipes/ultimate-thing?version=2019-01-01

然后让我们保持一致并为 1 使用相同的方法:

-- /recipes/ultimate-thing?version=latest

从这个角度来看,您的选项 1) - 使用查询参数 - 似乎是最自然的。

于 2019-03-18T17:36:34.090 回答