用于资源的不同版本的RESTful URL

Slo*_*oem 10 rest restful-url restful-architecture

我在概念上理解有关版本化资源的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
Run Code Online (Sandbox Code Playgroud)

我觉得每次我试图说服自己一种做法时,我觉得我缺乏理解为这种方法构建正确的理由.

许多铁路人员似乎更喜欢1,但我不知道如何清楚我何时想要创建新版本的配方,因为POST到特定资源(/ recipes/ultimate-thing)通常希望创建具有该名称的资源(如果它不存在),是否适合返回类似404的内容而不是创建它,并且仅发布到/ recipes以创建新配方然后允许POST到/ recipes/ultimate什么来创建一个新版本?此外,如何表达评论?没有版本我可以做/食谱/终极事物/评论,但/ recipes/utlimate-thing/comments?版本=最新看起来很丑,而2b看起来更明确"最新版本的最终版食谱的评论" ,2a似乎最干净.

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

我也在stackoverflow上看到2b,但似乎它可能过于冗长,因为你需要像/ recipes/ultimate-thing/version/latest/comments这样的东西.虽然这确实是最有意义的,如果我认为一个版本作为成分的集合与指令可以注释和配方是共享类似意图的版本的集合.

我真的很喜欢2a,但是我有什么方法可以解决这个问题吗?我错过了一些如何工作的东西,这使得它更有意义,似乎很多人都喜欢它?

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

我不确定这是否是一个非常适合的论坛,我只想讨论它,所以我理解为什么一种方法比另一种方法更好.

EJK*_*EJK 8

哇.好问题.我也发现REST最大的挑战之一就是风格,而不是严格的规范.这种风格似乎没有被充分理解,也没有什么可以强制执行它.

简答:Style#1:/ recipes/cake?version = 2

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

样式2和3似乎违反了其他REST约定,其中路径段表示ID和子资源.因此,style / recipes/cake/2看起来像ID为2的"蛋糕"资源./ recipes/cake/version/2使得"version" 看起来像是一个子资源,而实际上它是父类的属性资源.

  • 似乎使用任何类型的标题来指定将显示资源的哪个版本,都会破坏通过简单的超链接引用任何特定版本的能力。如果我确定我真的很喜欢我以前使用的蛋糕食谱,请说3次尝试,然后想把它展示给我的妈妈……标头会让我大吃一惊。我在回应您的建议吗? (2认同)

fum*_*chu 5

我去年年底刚刚实现了这个模式,并结合了 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
Run Code Online (Sandbox Code Playgroud)

不要将较长的 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,它收集所有数据并大量缓存)。