REST API子资源,数据返回?

时间:2016-06-30 08:15:18

标签: rest restful-architecture restful-url api-design

如果我们有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
  3. 我是否更正了URL的最后一个部分/文件夹,不包括查询字符串参数,应该是返回的资源..?

    如果是这样,数字1应该只返回订单数据而不包括客户数据。虽然数字2直接指向客户123并使用查询字符串参数来影响/过滤返回的客户数据,在这种情况下包括订单数据。

    这两个调用中的哪一个是对上述JSON的正确RESTful调用..? ......还是有一个秘密的3号选项..?

4 个答案:

答案 0 :(得分:1)

我认为有3个选项可以视为RESTful。

1) GET /customers/12 但总是包括订单。您是否有客户不想使用订单的情况?或者订单数组可以变得非常大吗?如果是这样,你可能想要另一种选择。

2) GET /customers/123,其中可能包含指向其订单的链接:

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

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

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

答案 1 :(得分:0)

您发布的JSON看起来像是

的结果
GET /customers/123

如果Customer资源包含Orders集合作为属性;或者你可以嵌入它们,或者提供它们的链接。

后者会产生这样的结果:

GET /customers/123/orders

会返回类似

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

答案 2 :(得分:0)

  

我正在寻找正确的RESTful方式来获取此数据

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

<强> TL; DR

  • REST并不关心URI设计 - 而是关注它的约束!
  • 客户端通过响应中包含的动态识别的超链接,通过服务器返回的可能操作来执行状态转换。
  • 客户端和服务器可以协商首选的超媒体类型
  • 不考虑嵌入整个(子)资源,而只考虑返回指向该资源的链接,以便客户端可以查找(如果有兴趣的话)

首先,只要URI是唯一的,REST就不关心URI设计。当然,简单的URI设计对于人类来说更容易理解,但是如果与HTML相比,实际链接可以隐藏在更有意义的文本背后,因此对于人类来说也是如此重要,只要他们能够找到链接和可以针对它执行操作。接下来,为什么你认为你的回应&#34;或API是RESTful?要调用API RESTful,API应该尊重几个constraints。在这些限制中有一个非常流行的着名词:超文本作为应用程序状态的引擎(HATEOAS)。

REST是我们每天使用的Web的概括概念。 Web会话的一个非常常见的任务是客户端请求服务器发送HTML文档的内容,该HTML文档包含大量链接和客户端可用于请求更多页面或流式传输视频的其他资源(或任何内容)。客户端上的用户操作可以使用返回的信息继续进行,请求新页面,向服务器发送信息等等。对于RESTful应用程序也是如此。这是REST简单定义为HATEOAS。如果你现在看看你的回复&#34;并使用HATEOAS约束进行双重检查,您可能会看到您的响应不包含任何开头的链接。因此,客户需要领域知识才能继续前进。

JSON本身并不是最好的超媒体类型IMO,因为它只定义数据的整体语法,但不包含任何语义,类似于普通XML,虽然可能有一些客户端可能用于验证的DTD或模式文档并检查其他地方是否有其他语义规则。有一些基于JSON构建的超媒体类型可能更适合像f.e. application/hal+json(可以在此blog post中找到基于JSON的超媒体类型的良好比较)。您当然有权定义自己的超媒体类型,但某些客户可能无法理解它的开箱即用。

如果你采取f.e.看看HAL您看到它定义了一个_embedded元素,您可以在其中放入某些子资源。在您的情况下,这似乎是理想的。根据您的设计,orders也可以单独作为资源,因此可以通过GET /orders/{orderId}本身访问。您也可以只包含指向该(子)资源的链接,而不是嵌入整个子资源,以便客户可以在感兴趣的情况下查找数据。

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

您当然也可以定义某种视图结构,其中一个视图仅按原样返回客户数据,而另一个视图返回客户数据,包括类似于response的订单,我给出的不是那么无关主题。

答案 3 :(得分:0)

资源(由完整 URL标识)与客户相同。只有 Representation 不同,有或没有嵌入式订单。

使用内容协商获取相同资源的不同表示形式。

请求

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
      }
    ]
  }
}