问题 连通性和HATEOAS


据说,在一个定义良好的RESTful系统中,客户端只需要知道根URI或几个众所周知的URI,客户端就应该通过这些初始URI发现所有其他链接。我确实理解这种方法的好处(解耦客户端),但对我来说,缺点是客户端需要在每次尝试访问某些内容时发现链接,即给定以下资源层次结构:

/collection1
collection1
  |-sub1
    |-sub1sub1
 |-sub1sub1sub1
         |-sub1sub1sub1sub1
    |-sub1sub2
  |-sub2
    |-sub2sub1
    |-sub2sub2
  |-sub3
    |-sub3sub1
    |-sub3sub2

如果我们遵循“客户端只需要知道根URI“方法,然后客户端应该只知道根URI,即上面的/ collection1,其余的URI应该由客户端通过超媒体链接发现。我觉得这很麻烦,因为每次客户端需要进行GET,比如说sub1sub1sub1sub1,如果客户端首先在/ collection1上执行GET并在返回的表示中定义跟随链接,然后在子资源上执行几次GET以达到所需的资源?或者我对连接性的理解完全错误?

最好的祝福, 苏雷什


2167
2017-07-14 07:24


起源

只有REST服务是无状态的,客户端不是。因此客户端可以记住以前的资源,它们的URL等...例如通过嵌套的导航菜单...... - inf3rno


答案:


当您尝试构建与使用API​​的用户代理程序流不匹配的REST API时,您将遇到此不匹配。

考虑运行客户端应用程序时,始终向用户显示一些初始屏幕。如果您将此屏幕上的内容和选项与根表示相匹配,则可用链接和所需的转换将很好地匹配。当用户在屏幕上选择选项时,您可以转换到其他表示,并且应更新客户端UI以反映新的表示。

如果您尝试将REST API建模为某种链接数据存储库并将客户端UI建模为一组独立的转换,那么您会发现HATEOAS非常痛苦。


6
2017-07-14 16:03



痛苦不一定是真的:我只有这个,一个项目集合的层次结构,以及客户端,当它启动时,它向下钻取一个或两个级别,并向下钻取到特定路径(客户端使用的路径)当它关闭时)客户端的缓存是持久的,因此所有请求都是有条件的,很少有新的表示通过线路进行,并且刷新可以通过完全脱离缓存在后台异步完成。 - mogsie
并且我同意将“API”建模为客户端应用程序的要求可以实现有效的会话,但我想重点是API通常应该迎合许多客户端,而不仅仅是那个客户端。 - mogsie
@mogsie在许多情况下,可能为多个客户端构建API,但我认为在大多数情况下,为特定案例构建API要高效得多。偶然重用是REST旨在提供的,而不一定是计划重用。 - Darrel Miller
确实如此。比方说,我建了一个 真 RESTful API;在设计API时,使用真实或假设的客户端可能会很好。 - mogsie


是的,客户端应用程序应该遍历链接是正确的,但是一旦发现了资源,保持对该资源的引用并使用它比一个请求更长的时间没有任何问题。如果您的客户有可能永久记住事物,它可以这样做。

考虑Web浏览器如何保留其书签。您可能在浏览器中有十个或一百个书签,并且您可能在页面层次结构中找到了其中一些书签,但浏览器会尽职尽责地记住它们而不需要记住找到它们所需的路径。

更丰富的客户端应用程序可以记住sub1sub1sub1sub1的URI,并在它仍然有效的情况下重用它。它可能仍然代表同样的事情(它应该)。如果它不再存在或因任何其他客户原因(4xx)而失败,您可以追溯您的步骤,看看您是否能找到合适的替代品。

当然Darrel Miller说:-)


4
2017-07-14 22:56



我喜欢你的比喻。有这样的想法,一切都联系在一起,没有联系到什么。从这个意义上说,谷歌成为所有导航的根源,但人们一直在保存快捷方式(书签)。但是,如果你不在谷歌,那么你基本上不存在。 - Alex
谢谢。或者,更确切地说:如果没有从Google到页面的路径,则它不存在。有点像谜语:“如果一棵树落在森林里,没有人在那里听到它;它会发出什么声音吗?” - mogsie


我不认为那是严格的要求。根据我的理解,客户端直接访问资源并从那里开始是合法的。重要的是你不要为状态转换执行此操作,即在/ foo1等操作后不会自动继续使用/ foo2。最初检索/ products / 1234编辑它似乎完全没问题。例如,服务器可以总是返回到/ shop / products / 1234的重定向以保持向后兼容(这对于搜索引擎,书签和外部链接也是期望的)。


0
2017-07-14 14:24