REST API 子资源,数据到 return?

REST API sub resources, data to return?

如果我们有 customersorders,我正在寻找获取此数据的正确 RESTful 方法:

{
  "customer": {
    "id": 123,
    "name": "Jim Bloggs"
    "orders": [
      {
        "id": 123,
        "item": "Union Jack Keyring",
        "qty": 1
      }, {
        "id": 987,
        "item": "London Eye Ticket",
        "qty": 5
      }
    ]
  }
}
  1. GET /customers/123/orders
  2. GET /customers/123?inc-orders=1

我是否更正 URL 的最后一个 part/folder,不包括查询字符串参数,应该是资源 returned..?

如果是这样,1 号应该只 return 订单数据,不包括客户数据。虽然数字 2 直接指向客户 123 并使用查询字符串参数 effect/filter 客户数据 returned,在这种情况下包括订单数据。

对于上面的 JSON..,这两个调用中哪个是正确的 RESTful 调用? ...或者是否有秘密数字 3 选项..?

您发布的 JSON 看起来像

的结果
GET /customers/123

假设客户资源包含订单集合作为 属性;或者,您可以嵌入它们,或向它们提供 link。

后者会导致这样的结果:

GET /customers/123/orders

这会 return 类似于

{
    "orders": [
      {
        "id": 123,
        "item": "Union Jack Keyring",
        "qty": 1
      }, 
      {
        "id": 987,
        "item": "London Eye Ticket",
        "qty": 5
      }
    ]
}

你有3个选项我认为可以考虑RESTful。

1) GET /customers/12 但始终包括订单。您是否遇到过客户不想使用订单的情况?或者订单数组真的可以变大吗?如果是这样,您可能需要其他选择。

2) GET /customers/123,可以在他们的订单中包含 link,如下所示:

{
  "customer": {
    "id": 123,
    "name": "Jim Bloggs"
    "orders": {
       "href": "<link to you orders go here>"
    }
  }
}

有了这个,您的客户必须发出 2 个请求才能获得客户及其订单。不过,这种方式的好处是您可以轻松实现干净的分页和订单过滤。

3) GET /customers/123?fields=orders 这类似于您的第二种方法。这将允许客户更有效地使用您的 API,但我不会走这条路,除非您真的需要限制从您的服务器返回的字段。否则,它会给您必须维护的 API 增加不必要的复杂性。

I'm looking for the correct RESTful way to get this data

只需对指向生成此数据的资源的 URI 执行 HTTP GET 请求!

TL;DR

  • REST 不关心 URI 设计 - 但关心它的约束!
  • 客户端通过可能的操作执行状态转换 return 服务器通过响应中包含的动态识别的 hyperlink 编辑。
  • 客户端和服务器可以就首选超媒体类型进行协商
  • 与其嵌入整个(子)资源,不如考虑仅 return 将 link 添加到该资源,以便客户可以在感兴趣时查找它

首先,REST 并不真正关心 URI 设计,只要 URI 是唯一的即可。当然,一个简单的 URI 设计对人类来说更容易理解,但如果与 HTML 相比,实际的 link 可以隐藏在更有意义的文本后面,因此对人类来说也不是那么重要,只要他们能够找到 link 并可以对其执行操作。接下来,为什么你认为你的"response"或API是RESTful?要调用 API RESTful,API 应该尊重一对 constraints。在这些约束中有一个非常流行的词:超文本作为应用程序状态引擎 (HATEOAS)。

REST 是我们每天使用的 Web 的广义概念。 Web 会话的一个非常常见的任务是客户端请求服务器发送 HTML 文档,其中包含大量 links 和客户端可以用来请求更多页面或流式传输视频的其他资源(管他呢)。客户端上的用户操作可以使用 returned 信息进一步处理、请求新页面、向服务器发送信息等。这同样适用于 RESTful 应用程序。这是 REST 简单定义为 HATEOAS。如果您现在查看 "response" 并仔细检查 HATEOAS 约束,您可能会发现您的响应不包含任何 link 开头。因此,客户需要领域知识才能继续前进。

JSON 本身并不是最好的超媒体类型 IMO,因为它只定义了数据的整体语法但不携带任何语义,类似于普通的 XML 虽然可能有一些 DTD或模式,客户端可以用来验证文档并检查其他地方是否有进一步的语义规则。有一些建立在 JSON 之上的超媒体类型可能更适合 f.e。 application/hal+json (A good comparison of JSON based hypermedia types can be found in this blog post)。您当然有权定义自己的超媒体类型,尽管某些客户可能无法直接理解它。

如果你服用f.e。看一下 HAL 你会发现它定义了一个 _embedded 元素,你可以在其中放入某些子资源。这对你的情况来说似乎是理想的。根据您的设计,orders 本身也可以是一个资源,因此可以通过 GET /orders/{orderId} 本身访问。您也可以只将 link 包含到该(子)资源中,而不是嵌入整个子资源,以便客户端可以在感兴趣时查找数据。

如果在某些情况下您只想 return 客户数据,而在其他情况下您还想包含订单数据,您可以 f.e。为两者定义不同的超媒体类型(基于 HAL f.e。),一个 return 仅包含客户数据,而另一个还包括订单数据。这些类型可以这样命名:application/vnd.yourcompanyname.version.customers.hal+jsonapplication/vnd.yourcompanyname.version.customer_orders.hal+json。虽然与向请求添加简单的查询参数相比,这肯定是开发开销,但语义更清晰,文档开销是关于超媒体类型(或表示)而不是 HTTP 操作。

您当然也可以定义某种视图结构,其中一个视图仅 return 原样显示客户数据,而另一个视图 return 显示客户数据,包括类似于 我给出了一个不太相关的话题。

Resource(由completeURL标识)相同,一个客户。只有 表示 不同,有或没有嵌入订单。

使用内容协商为同一资源获取不同的表示。

请求

GET GET /customers/123/
Accept: application/vnd.acme.customer.short+json

回应

200 OK
Content-Type: application/vnd.acm.customer.short+json

{
  "customer": {
    "id": 123,
    "name": "Jim Bloggs"
  }
}

请求

GET GET /customers/123/
Accept: application/vnd.acme.customer.full+json

回应

200 OK
Content-Type: application/vnd.acme.customer.full+json

{
  "customer": {
    "id": 123,
    "name": "Jim Bloggs"
    "orders": [
      {
        "id": 123,
        "item": "Union Jack Keyring",
        "qty": 1
      }, {
        "id": 987,
        "item": "London Eye Ticket",
        "qty": 5
      }
    ]
  }
}