Link 到 REST API 中的另一个资源:按其 ID 还是按其 URL?

Link to another resource in a REST API: by its ID, or by its URL?

我正在使用 创建一些 API,因此使用的语言是 JSON。

假设我需要代表这个资源:

{
    "id" : 9,
    "name" : "test",
    "customer_id" : 12,
    "user_id" : 1,
    "store_id" : 3,
    "notes" : "Lorem ipsum example long text"
}

通过 ID 引用其他资源是否正确(1213),或者我应该指定这些资源的 URL(即 /customers/12/users/1/stores/3)?

我没有使用 HATEOAS,我有点困惑。

我看过其他流行的 API(Facebook、Spotify),我认为以下是最好的方法:

{
   "id" : 9,
   "name" : "test",
   "customer" : {
      "id": 12,
      "href": "/customers/12"
   },
   "user" : {
      "id": 1,
      "href": "/users/1"
   },
   "store" : {
      "id": 3,
      "href": "/stores/3"
   },
   "notes" : "Lorem ipsum example long text"
}

DO 在您的响应中包含 absolute 个实体 URI(例如 /customers/12 甚至 http://www.example.com/customers/12)。

不要在响应中仅包含一个实体的 ID(例如 12),因为那样您会强制客户端自己组合资源 URI。为此,他们需要预先了解有哪些 URI,而您将失去对服务器端 URI space 的控制。

(如果服务器指示客户端如何操作,例如通过发送 URI template 和 ID,则让客户端将 URI 放在一起是可以的;但如果这样做,它也可以发送结果 URI。)

另请参阅:

  • "A REST API should be entered with no prior knowledge beyond the initial URI (bookmark)."
  • "A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). Servers must have the freedom to control their own namespace. Instead, allow servers to instruct clients on how to construct appropriate URIs[.]"
  • HAL,它指定了将 link 相关资源放入您的响应中的标准方法。

  • JSON API —“在 JSON 中构建 API 的规范”

  • 以上建议不仅适用于其他资源的 ID(即“外键”,例如您的 customer_id);您还将资源自己的 id 变成所谓的“self link”;见 SO question "What is the importance of the self link in hypermedia APIs?".

示例:

您的原始资源可以重新设计如下:

{
  "type": "foobar",
  "id": "9",
  "links": {
    "self": "//example.com/foobars/9"
  },
  "cashier": {
    "type": "user",
    "id": "1",
    "links": {
      "self": "//example.com/users/1"
    }
  },
  "customer": {
    "type": "customer",
    "id": "12",
    "links": {
      "self": "//example.com/customers/12"
    }
  },
  "name" : "test",
  "notes" : "Lorem ipsum example long text",
  "store": {
    "type": "store",
    "id": "3",
    "links": {
      "self": "//example.com/stores/3"
    }
  }
}

注意几点:

  • 每个资源(被传输的主要对象,也包括子资源)都附有一些自我描述的元数据,例如typeidlinks.
  • 子资源可以包含部分或完整数据。只要self-link在,客户端就知道从哪里得到完整的资源
  • type 可能看起来有些冗长;通常,您隐含地知道期望什么样的对象。 属性 可以帮助验证,还可以让您有机会区分对象类型和角色(例如,上例中的 cashier is-a user)。