【问题标题】:RESTful HATEOAS Client UrlRESTful HATEOAS 客户端网址
【发布时间】:2023-03-13 07:21:01
【问题描述】:

我有理由确定我了解 HATEOAS 设计的服务器端——在响应中返回状态 URL——但我对如何设计客户端来接受这些有点困惑。

例如,我们访问 //somehost.com/resource/1 上的资源 - 这为我们提供了资源数据和链接。我们假设返回到 //somehost.com/resource 的 POST,表示一个“新”操作。现在我知道将一些数据发布到该 url 会创建一个新资源并提供响应,但是发布该数据的表单在哪里?我已经看到 //somehost.com/resource/1/new 提供了一个 POSTS 到 /resource 的表单的实现,但是该 URL 本身包含一个动词,并且似乎违反了 REST。

我认为我的困惑在于我在同一个应用程序中实现了一个 RESTful API 和一个使用它的客户端。

这种事情有什么最佳实践吗?

【问题讨论】:

  • 您在询问架构。一些 API 和客户端使用它,但有些更紧密耦合并且只是基础,例如。在文档上(而不是在资源表示上)。还要确保模式在“更新”调用使用的内容和“创建”调用的预期内容之间是通用的(我已经看到这两个完全不同的方法,在我看来这只是不好的做法,因为它引入了一些不一致) .

标签: rest hateoas


【解决方案1】:
我已经看到 //somehost.com/resource/1/new 提供了一个 POSTS 到 /resource 的表单的实现,但是该 URL 本身包含一个动词,并且似乎违反了 REST。

这是不正确的。 包含动词的 URI 本身并不违反任何 REST 约束。只有当 URI 代表一个动作时,这才成为违规。如果您可以对 URL 执行 GET 请求并接收一些有意义的资源(例如“创建新资源”表单),那么这就是完美的 RESTful,也是一种很好的做法。

我自己的 API 和你描述的完全一样:/{collection}/new 返回一个表单。 /new 只是假设的 /new-resource-creation-form 的简写,仍然代表名词,并且仅支持 GET 请求(不支持 HEAD、OPTIONS 和 TRACE)。
HATEOAS 禁止的是要求用户代理知道,为了创建新资源,它必须将/new 添加到集合的名称中。

基本上,如果您将 API 实现为 (X)HTML,并且可以 surf it in a browser 并执行所有操作(在 HTML 和浏览器赶上 HTTP 之前,非 POST 表单提交可能需要 AJAX),那么它符合REST 的超媒体约束。

EDIT 从 cmets 提升:

只要响应否定了对先验知识的任何需求,它就符合超媒体约束。如果客户端声称理解 HTML,并且您发送回包含指向外部样式表或 javascript(无论托管在何处)的链接的响应,客户端需要能够正确呈现页面,那么可以合理地说满足约束。客户端应该知道如何处理它声称支持的所有媒体类型。普通的人类网络浏览器是客户端对任何一个 HTTP 服务(网站)没有带外知识的完美示例。

明确地说,网站是一种 HTTP 服务。 Web 浏览器不会以不同的方式对待不同的网站。为了在 Amazon 上搜索产品,您在 http://amazon.com/ 加载 Amazon 服务端点并点击链接或填写该响应中提供的表格。为了在 eBay 上搜索产品,您在 http://ebay.com/ 加载 eBay 服务端点并执行相同操作。
浏览器事先并不知道搜索 eBay 必须这样做this,但搜索 Amazon 你必须这样做that。浏览器是无知的。其他 HTTP 服务的客户端也应该是无知的。

【讨论】:

  • 谢谢 Nicholas,这正是我正在寻找的答案。
  • Nicholas,使用 HTML 作为响应的默认内容类型来实现 API 会排除客户端与 API 的逻辑分离吗?例如,当客户端 HTML 屏幕的布局来自以下域时,HATEOAS 将如何工作:example.com/* 但该屏幕中显示的数据来自 api.example.com/* 这种类型的设置可行吗?
  • @Mackers 只要响应否定了对先验知识的任何需求,它就符合超媒体约束。如果客户端声称理解 HTML,并且您发送回包含指向外部样式表或 javascript(无论托管在何处)的链接的响应,客户端需要能够正确呈现页面,那么可以合理地说满足约束。客户端应该知道如何处理它声称支持的所有媒体类型。普通的人类网络浏览器是客户端没有关于 HTTP 服务(网站)的带外知识的完美示例。
  • @Mackers 明确地说,网站是一种 HTTP 服务。 Web 浏览器不会以不同的方式对待不同的网站。为了在 Amazon 上搜索产品,您在 http://amazon.com/ 加载 Amazon 服务终端节点并点击链接或填写该响应中提供的表格。为了在 eBay 上搜索产品,您在 http://ebay.com/ 加载 eBay 服务端点并执行相同操作。浏览器事先并不知道搜索 eBay 必须执行this,但搜索 Amazon 必须执行that。浏览器很笨。其他服务的客户也应该如此。
【解决方案2】:

是的,您可以提供一个返回资源创建表单的 URI。可以想象,该表单可用于动态发现构建新资源所需的元素(但您需要确定这在机器对机器环境中的实际应用程度)。

除非有要求以某种方式 API 具有精确的浏览器可浏览等效项,否则媒体类型的文档将描述所需的元素。

请记住,媒体类型的文档和资源允许的 HTTP 动词并不违反 RESTful 原则。以SunCloud API 为例。

确实,根据你的例子,POST'ing to

//somehost.com/resource

创建一个新资源比首先返回一个表单更标准

//somehost.com/resource/1/new

然后发布到

//somehost.com/resource

无论如何。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 2013-04-14
    • 2018-03-18
    • 1970-01-01
    • 2013-09-16
    相关资源
    最近更新 更多