【问题标题】:REST - Typed resources vs HYDRA classesREST - 类型化资源与 HYDRA 类
【发布时间】:2019-03-31 01:17:03
【问题描述】:

来自菲尔丁的文章 (https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven):

REST API 绝不应该有对客户端很重要的“类型化”资源。规范作者可以使用资源类型来描述接口背后的服务器实现,但这些类型必须是不相关的并且对客户端不可见。对客户端重要的唯一类型是当前表示的媒体类型和标准化关系名称。 [同上]

在 HYDRA 中,类可以像这样记录在 API 文档中:

supportedClass:
  '@id': 'schema:Event'
    supportedProperty:
      - property:
          '@id': eventName

它不被视为类型化资源吗? JSON-LD 中甚至还有一个@type 字段。我理解标准化关系名称的重要性,因为它们为客户提供了对资源或属性进行有用操作所需的语义、格式和约束,但是通过限制 API 文档中可能的关系范围,我们实际上是在声明类型(类)。

没有类,客户端将不知道将出现什么关系,并且编写客户端以使其知道大多数关系类型(例如来自 schema.org)是不切实际的。

这个约束的确切含义是什么,它在实践中如何有用? HYDRA 不尊重这一点吗?


我问这个是出于理论上的兴趣。在实践中,我并不关心我的 HTTP API 是否满足所有限制(如果它可用)。

【问题讨论】:

  • Jorn Wildt 在this matter 上写了一篇不错的博文
  • 谢谢,请阅读。似乎他的理解在某种程度上与我相似。我认为,从可用性方面来看,拥有具有不同词汇表的通用媒体类型(JSON-LD 和 schema.org)或具有特定于域的媒体类型(vCard)是同构的。只是“类型”在其他地方编码。我会说这归结为个人喜好使用什么。对我来说,如果我编写跨多个域的 API,那么 hydra 是首选,因为它具有统一的接口。如果需要,它稍后可以支持特定的媒体类型。会阅读那篇文章中引用的文章。
  • 这篇博文或 Fieldings 声明的核心点是,客户端不应该从资源的名称(即/api/customers)中推断出资源的类型,而是使用内容协商来通知服务器:客户端能够处理以下媒体类型,服务器应以客户端理解的表示形式返回信息。 Fielding 还指出,REST 架构的重点应该是指定媒体类型和有意义的链接关系名称,而不是过度工程化的 URI
  • 没错,这也是因为uris是透明的,甚至uri的结构都是事先不知道的,所以无论如何也不可能。链接关系应该记录取消引用时 URI 的范围,我只是想指出,它可以通过引用特定的媒体类型(vCard)来完成 - Jorn Wildt 似乎更喜欢这个 - 或者通过引用来自json-ld 的词汇表 (schema.org/CreditCard)。困扰我的是第二种情况,因为词汇“类型”是一种类型(或者似乎首先,这就是我的答案试图解决的问题)。

标签: rest api-design json-ld hypermedia hydra-core


【解决方案1】:

我想我明白“类型化资源”(正如 Fielding 所说的那样)和在 JSON-LD/HYDRA 等媒体类型中定义的类型或类之间的区别。我正在回答我自己的问题,但如有必要,请扩展/更正它。


TL;DR 我的理解是这种约束将类型称为资源的预定义表示(或结构),并提倡记录可能的关系和媒体类型处理规则而不是这种结构。这些关系仍然可以归类为“类型”,但表示方式不会僵化。


属性通常具有预定义的名称,并在其封闭类型的上下文中被理解。这意味着服务器/客户端应该就这个命名约定达成一致,以便处理这些类型,并且在一种类型中与在不同类型中命名相同的字段可能具有完全不同的语义。它产生了一个刚性的资源结构。

另一方面,像 JSON-LD 这样的超媒体类型并不以常见的方式使用属性。他们改为使用一些嵌入信息(@context)来定义属性的语义,可以是其他实体、值对象、引用等......

通过处理具有给定超媒体类型的资源,属性被转换为一些定义明确的关系,通常在词汇表中定义。这意味着相同的关系可以用于多种类型,例如PersonBook 中的 name 字段可以引用它们与值对象之间的 https://schema.org/name 关系(例如简单的字符串名称)。

这通过允许客户端对关系类型使用通用词汇表并通过定义媒体类型的处理规则来将客户端与服务器解耦,因此建议在直接以序列化格式使用资源之前对资源进行预处理(如你可能不知道它是如何返回的)。

例如:

{
  "@context": "http://schema.org/",
  "@type": "Person",
  "@id": "http://srv.org/users/1",
  "name": "Jane Doe",
  "telephone": "(425) 123-4567",
  "url": "http://www.janedoe.com"
}

是相同的资源

{
  "@context": {
    "a": "http://schema.org/name",
    "b": "http://schema.org/telephone",
    "c": {
      "@id": "http://schema.org/url",
      "@type": "@id"
    }
  },
  "@type": "http://schema.org/Person",
  "@id": "http://srv.org/users/1",
  "a": "Jane Doe",
  "b": "(425) 123-4567",
  "c": "http://www.janedoe.com"
}

甚至是

[
  {
    "@id": "http://srv.org/users/1",
    "@type": [
      "http://schema.org/Person"
    ],
    "http://schema.org/name": [
      {
        "@value": "Jane Doe"
      }
    ],
    "http://schema.org/telephone": [
      {
        "@value": "(425) 123-4567"
      }
    ],
    "http://schema.org/url": [
      {
        "@id": "http://www.janedoe.com"
      }
    ]
  }
]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-30
    • 2011-11-25
    相关资源
    最近更新 更多