【问题标题】:Link relation granularity vs precision in a custom media type?自定义媒体类型中的链接关系粒度与精度?
【发布时间】:2012-03-17 00:24:19
【问题描述】:

我正在为 RESTful API 设计自定义媒体类型,并研究了一些“标准”链接关系的类型和语义,以便为我的设计提供一些指导。

为了演示这个问题,假设我有一个资源,我可以对其执行标准的读取、更改、删​​除方法,并且我分别使用 GET、PUT 和 DELETE 的 HTTP 习惯用法来实现这些方法。

我可以合理地(重新)使用RFC5023 中定义的“编辑”链接关系(来自IANA link registry),其中指出:

"..."edit"的值指定href属性的值 是可编辑成员条目的 IRI。当出现在一个 atom:entry,href IRI 可用于检索、更新和删除 该条目所代表的资源......”

通过这种方式,用户代理可以理解具有“编辑”关系的链接将允许对资源进行 GET、PUT 和 DELETEd。

然而,问题就在这里,如果资源状态被编辑,使得资源现在只支持 GET 和 DELETE 操作,“编辑”关系就不再精确。

为了保持精度,我需要 i) 选项 A:指定另一个仅支持 GET & DELETE 的(复合)链接关系,或 ii) 选项 B:为每个可能的状态转移指定单独的链接并使用适当的表示允许的状态转移。后一种方法提供了精确性,但似乎过于冗长。

或者,(选项 C)我可以保留“编辑”关系并接受缺乏精度,即链接将传达 GET、PUT、DELETE 语义,但尝试 PUT 的用户代理会遇到HTTP 错误“405 - 方法不允许”。但是,我对这种方法也不满意,因为它向客户端暗示了不受支持的状态转换。

总之,问题是平衡链接关系通用性和精度的最明智的方法是什么?

【问题讨论】:

  • 交叉发布到 API Craft link

标签: api rest hateoas hypermedia


【解决方案1】:

经过认真调查后,我得出结论,我正在尝试解决错误的问题。与其关注链接关系定义中 HTTP 动词的粒度,更精细的问题是“应该将 HTTP 习语(动词)合并到链接关系中吗?”。

我曾使用 AtomPub 作为如何进行链接关系(用于 REST)的参考,结果证明这是一个错误。在AtomPub mail archive Roy Fielding 中建议(在 REST 术语中)“编辑”方法是错误的,并得出结论认为这是不必要的。该论点表明存在其他 (HTTP) 机制来传达此类属性,因此它们在 'rel' 属性中没有位置。

邮件存档中没有明确说明其他机制,但我怀疑它们包括以下选项:

  1. 让用户代理尝试检查响应(2xx 或 4xx),或者
  2. 使用 OPTIONS 向资源询问允许的操作,或
  3. 在成功的 GET 请求中包含一个“允许”标头以传送 允许对用户代理进行资源操作。

有趣的是,Roy 认为'Allow' header 是“一种超文本形式”。

总之,我自己的问题的答案是:

"不要将 HTTP 操作混为 'rel' 的含义 "

"使用(提供的)HTTP 机制来确定允许的资源操作"

编辑:我应该补充一点,POST 作为数据接收器有一些特殊用途,这些规则需要稍微弯曲,但它们是一种特殊情况。

【讨论】:

    【解决方案2】:

    WRML 规范采用了一种方法,即每个“链接”对象都可以有一个 rel 属性。

    GET /dogs/1
    {
        "links" : {
            "self" : {
                "href" : "http://api.example.com/dogs/1
                "rel" : "http://api.example.com/relations/self"
            }
        }
    }
    

    然后客户端可以跟随 rel url

    GET /relations/self
    {
       "name" : "self"
       "description" : " A reference back to the same object you are currently interacting with" 
       "method" : "GET"
    }
    

    规范确实建议每个 rel 都应该指定一个方法。这样做的好处是可以非常明确地告诉客户他们应该做什么,并限制所需的带外知识的数量。我个人在这方面来回反复,因为我认为说某些“rel”提供多种 HTTP 方法是有价值的。想象一下狗主人的链接

    GET /dogs/1
    {
        "links" : {
            "self" : {
                "href" : "http://api.example.com/dogs/1
                "rel" : "http://api.example.com/relations/self"
            }
            "owner" : {
                "href" : "http://api.example.com/owner/1
                "rel" : "http://api.example.com/relations/owner"
            }
        }
    }
    

    让“所有者”暗示 GET 和 PUT 会很好,因为它们都是有效的操作。与此相反的是,您应该始终需要在进行更新之前进行 GET,因此在检索资源之前提供该信息的价值是错误的形式。

    所以我猜所有的人都说我会投票给选项 B。

    【讨论】:

    • Daniel - 获得 WRML 视图很有趣 - 谢谢。作为比较点RFC5988 允许在同一链接中存在多个关系,例如 rel="self edit" 减少了冗长,并允许您提到的多样性。 RFC 还指出“客户端不应自动访问”rel URI,但这主要是服务器负载问题。给定一个合适的缓存策略,我认为这是一种合理的方法。
    【解决方案3】:

    另一种选择是离开“编辑”关系,并允许想知道他们当前可以对资源执行什么操作的消费者使用 OPTIONS HTTP 方法发出请求,服务器可以返回带有 @ 的响应987654321@ 标头指示在给定当前状态的资源上允许的方法。

    它不会在没有额外请求的情况下为您提供 PUT 操作的可用性,但它相当“干净”并允许您使用标准关系和 HTTP 机制。

    【讨论】:

    • 皮特,谢谢。虽然 HTTP OPTIONS 方法提供了一种实用且标准的发现方法,但我认为它有损于链接的 href 的语义应该由 rel 传达的事实。如果不是,那么 rel 属性的“意义”就被稀释了。我很欣赏“rel”属性的精确含义,或者实际上来自 OPTIONS 的响应返回了资源方法的时间点视图——这可能会改变。如果资源已更改,则可能会出现 405。但是,我的重点是在这些不同的场景中定义 rel 的含义。
    • 很公平。我也在关注 API-Craft 列表,因为我也很好奇其他人要说什么。
    • Pete,经过 大量 的调查工作,我想我现在对这个问题有了合理的理解。您对“使用选项”的回答是解决方案的一部分 - 请参阅我自己的回答中的漫谈。
    • 感谢您对进一步研究结论的全面跟进回应!
    猜你喜欢
    • 1970-01-01
    • 2015-12-22
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 2015-08-22
    • 1970-01-01
    • 2018-07-23
    • 2013-01-28
    相关资源
    最近更新 更多