【问题标题】:Returning objects with multiple types in a RESTful way以 RESTful 方式返回具有多种类型的对象
【发布时间】:2014-03-09 08:19:56
【问题描述】:

我目前正在设计一个 API 来处理来自移动客户端的请求。为了在后端和客户端之间实现某种程度的解耦,我想以 RESTful 方式定义 Web 服务。我面临的挑战是一次调用返回多个具有不同类型的对象。

假设我们有以下模型:

  • 港口 ...顶级入口
  • 船棚 ...分配到特定港口 (0..n)
  • ...分配给特定的船棚 (0..n),或直接分配给港口 (0..n)

据我了解 REST,如果我现在想显示港口中的所有船只和棚屋,我会发送两个请求:

/harbours/{harbour_id}/boats 返回所有船只的列表。棚屋中的船将包含一个链接到它们所在的棚屋的 ID

/harbours/{harbour_id}/sheds返回所有棚子的列表

由于我想在移动场景中使用 Web 服务,因此将这两个调用合二为一是理想的。然后,这可以返回嵌套有棚对象的船列表,或者并列返回两种对象类型:

/harbours/22/boats

[
   {
      "id":1,
      "boatName":"Mary",
      "boatShed":{
         "id":1,
         "shedName":"Dock 1",
         "capacity":55
      }
   },
   {
      "id":2,
      "boatName":"Jane",
      "boatShed":{
         "id":1,
         "shedName":"Dock 1",
         "capacity":55
      }
   }
]

/harbours/22/boats

{
   "boats":[
      {
         "id":1,
         "boatName":"Mary",
         "boatShedId":1
      },
      {
         "id":2,
         "boatName":"Jane",
         "boatShedId":1
      }
   ],
   "sheds":[
      {
         "id":1,
         "shedName":"Dock 1",
         "capacity":55
      }
   ]
}

我现在的问题是,这些方式中哪一种更接近 REST 背后的理念,还是根本不是 RESTful?

【问题讨论】:

  • 第一个选项更加 RESTful。如果您要船,第二个返回棚子。

标签: rest mobile


【解决方案1】:

创建一个包含Boat ShedBoat 信息的Harbour 模型。如果我在 Java 中实现服务,那么我会做这样的事情:

class Boat{
...
}

class BoatShed{
...
}

class Harbour{
List<Boat> boats;
List<BoatShed> boatSheds;
...
}

您可以创建一个类似/api/harbours/{harbourId} 的 API。

根据您的问题,您想在harbour 中显示所有船只和棚屋,比如id=1234,您可以提出这样的请求:

GET /api/harbours/1234

这将返回Boats 的列表和Boat Sheds 的列表,如下所示:

{
"boats":[
  {
     "id":1,
     "boatName":"Mary",
     "boatShedId":1
  },
  {
     "id":2,
     "boatName":"Mary2",
     "boatShedId":2
  }
],
"sheds":[
  {
     "id":1,
     "shedName":"Dock 1",
     "capacity":55
  },
  {
     "id":2,
     "shedName":"Dock 2",
     "capacity":50
  }
  ]
}

编辑 由于您想通过发送一个请求并排获得boatsSheds,根据REST API 设计原则,api/hourbours/{id} 看起来不错。

在请求boats 时获取所有sheds 并不符合理想的REST API 设计,但如果您想达到相同的效果,您可以执行以下操作。

如果你想要那样,那么 first one /api//harbours/{id}/boats 对我来说看起来不错。

【讨论】:

  • 感谢您的回答乔希,不幸的是,这并没有回答我的问题。我想知道您将如何以适当的 REST 样式进行操作。我不清楚在遵循 REST 时,像所描述的模型是要并排返回还是嵌套返回。
  • 这里的问题与 max_i 的问题相同:由于我处于移动场景中,因此我希望将传输的数据保持在最低限度。因此,在请求 /harbours 时,我不想获得所有港口和船只的列表。这会导致 /harbours 和 /harbours/{id} 返回不同模型的问题。
  • 是的。因此,正如我所提到的,您可以采用第一种方法。
【解决方案2】:

正如@Tarken 提到的/boats 请求不应返回顶层的棚子(因为网址假定您要求收集资源Boat

如果你有如下定义的关系

Harbour:
    boats: Boat[]
    sheds: Shed[]

Shed:
    boats: Boat[]

Boat:
    harbour: Harbour
    shed: Shed

/harbours/ID 然后返回带有boatssheds 关系集的Harbour 表示。

{
  boats: 
  [
    { Boat },
    { Boat },
    ..
  ],
  sheds: 
  [
    { Shed },
    { Shed },
    ..
  ],
  ...
}

这里没有什么是违反 restful 原则的 - url 唯一地标识一个资源,资源表示可以是任何东西,也可以链接到其他资源。

【讨论】:

  • 那么如果我们这里有嵌套模型也没问题?
  • 如果我要求 /harbours 会返回什么?由于它是一个移动场景,因此最好按需请求。如果我已经归还了那里所有的船和棚子,我已经传输了相当多的数据,我可能不需要。
  • @Paul 如果 api 实体具有丰富的表示形式(例如链接到棚子和船的 harobour),最好添加字段选择器支持并在查询时指定您需要哪些字段。因此,您可以执行/harbours?_fields=id,name 之类的操作,将棚屋和船只排除在查询之外。这样,您不仅可以减少传输数据的大小,还可以消除额外的数据库调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多