RESTful多对多的可能性?

12

如何为REST post表示复杂资源?

你好,目前我有一个应用程序,当用户点击“保存”时,它会遍历所有表单元素并创建一个管理以下内容的大型对象:

  var = params = [{ 
   attributes1: form1.getValues(),
   attributes2: form2.getValues(),  
.. ..
}];
我通过RPC POST将这个大型对象发送到我的“实体”模型服务,我希望为其持久化数据的实体非常复杂。总体而言,数据分散在约30个表中。为了解释我的实际问题,这个“实体”是一个建筑物(如物业/房屋/公寓)。
我想要的是将我的混乱转变为用于保存属性的RESTful API。我面临的问题是,对于跨越单个表的单个模型保存细节是可以的。但是,当模型具有:
- 多对多关系 - 一对多关系 - 一对一关系
时,如何构造我的数据对象进行传输?
例如:
以下是我可能在一个属性上拥有的内容和示例数据的简化版本。
propertyId: 1,
locationId: 231234,
propertyName: "Brentwood",
kitchenFeatures: [
             { featureId: 1, details: "Induction hob"},
             { featureId:23, details: "900W microwave"}
],
propertyThemes: [ 12,32,54,65 ]

实际上还有更多细节,但你可以大致了解。 kitchenFeatures 是一个典型的多对多关系的例子,我有一个包含所有特征的 featuresTable 表格:

`featureId`, `feature`
1             "Oven Hob"  
23            "Microwave"

而 propertyThemes 就是另一个多对多关系的例子。

我应该如何组织我的“对象”发送到 RESTful 服务中?这可能吗?

例如,如果我想要保存这个属性,我会将其发送到:

http://example.com/api/property/1

3个回答

10

我在这里采用的方法是超媒体和链接:

/property
/property/{id}
/property/{id}/features/{id}

根据您的领域,您甚至可以使用以下方法:

/property/{id}/features/{name}

或者

/property/{id}/features/byname/{name}

因此,您可以执行REST 操作并提供JSON或XHTML 超媒体

属性详情:

Request: GET /property/1
Response:
{
  ..
  "name": "Brentwood",
  "features": "/property/1/features"
  ..
}

Brentwood的特点:

GET /property/1/features
{
  ..
  "Kitchen": "/property/1/features/1",
  "Dog Room": "/property/1/features/dog%20room",
  ..
}

GET /property/1/features/1
{
  ..
  "Induction hob": "/property/1/features/1/1",
  "900W microwave": "/property/1/features/1/23",
  "nav-next" : "/property/1/features/dog%20room",
  ..
}

要添加关系,您可以这样做:

POST /property/1/features
{
  ..
  "Name": "Oven Hob"
  ..
}

如果您已经知道关系,那么可以使用PUT:

PUT /property/1/features/23
{
  ..
  "Name": "Oven Hob"
  ..
}

您可以服务于多种媒体类型:

GET http://host/property/1/features/dog%20room.json

GET http://host/property/1/features/dog%20room.xhtml

对于 xhtml 响应,响应可以使用如下名称链接:

..
 <a href="http://host/property/1/features/1" rel="prev">Kitchen</a>
..

除了我上面没有包含的响应代码之外,还有其他方面的REST可以使用。

因此,为了建模关系,您可以使用链接,它本身可以是可以使用GET、PUT、POST和DELETE甚至自定义动词(如ASSOCIATE或LINK)进行操作的资源。但前四个是人们习惯使用的。请记住,PUT是幂等的,但POST不是。请参见PUT vs POST in REST

编辑:您可以将链接分组成JSON数组,以为您的超媒体提供结构。


4
我认为你实际上是在问,“如何以适合在POST中传输的形式表示复杂的数据?”这与REST关系不大,更多的是与媒体类型的选择有关。我建议从纯JSON表示开始,使用数组和交叉引用的ID字段来映射关系。当然,你也可以使用XML来完成这个任务。
你提供的示例看起来非常正确。你只需要确保双方(浏览器和服务器)都同意使用你所选择的媒体类型的结构和解释方式即可。

布莱恩,是的,你说得对。我的问题实际上可以概括为:“如何表示一个包含数十个关系的复杂资源”。我实际上找不到许多关于这个主题的文章/资源。如果我只引用ID,那不符合REST原则,对吧? - Layke
当然,是的。我唯一要确保的是您传输整个对象图的完整表示,而不仅仅是部分内容。当然,您可以采用“超纯”的方法,将单个POST调用降级为大量的POST调用(每个需要创建的对象一个),但我认为这将是一个武断的决定,只会迫使您进行数十甚至数百次远程调用。这真的取决于您的应用程序需要什么。 - Brian Kelly

2

我正在处理与这完全相同的事情。我选择不在任何地方使用id,而是在通常需要id的地方都使用url。

因此,在您的情况下,kitchenfeatures可以简单地是一个包含URL的数组:

/feature/1
/feature/23

并且主题可以

/propertyTheme/12
/propertyTheme/32
etc..

在多对多关系的情况下,我们会整体更新所有关系。通常我们只需删除现有数据,并插入新的关系。

对于一对多的关系,有时我们会在合适的情况下扩展url。如果您在“属性”上拥有评论功能,则可能如下所示:

/property/1/comment/5

但这取决于我们的情况,对于其他情况,我们将其放在顶层命名空间中。

这对您有帮助吗?


这难道不意味着您的客户端会向服务器指示每个新创建的对象要使用哪个URI吗?鉴于URI的外观应该是服务器的决定,我会尽量避免这种情况。或者您的客户端已经从之前的POST请求中获取了这些URI吗? - Brian Kelly
由于你提到了多对多,我认为你所涉及的(功能)已经存在。因此客户端会有这些URI可用。这个假设是错误的吗? - Evert
我认为我们需要等待OP回答这个问题。之前我以为客户会一次性创建整个图表,但事实并非如此。 - Brian Kelly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接