问题 RESTful多对多可能吗?


如何为REST帖子表示复杂资源?

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

  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


1479
2018-03-24 19:03


起源



答案:


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

/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"
  ..
}

布伦特伍德的特点:

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。看到 REST中的PUT与POST

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


10
2018-04-02 15:21





我想你真的在问,“我如何以适合在POST中传输的形式表示复杂数据?”,对吧?它与REST关系不大,而与您选择的媒体类型有关。我建议从纯JSON表示开始,使用数组和交叉引用的ID字段来映射关系。当然,您也可以使用XML执行此操作。

你给出的例子看起来对钱。您只需要确保双方(浏览器和服务器)就您使用的媒体类型的结构和解释达成一致。


3
2018-03-24 22:31



布赖恩,是的,你是对的。我的问题实际上归结为:“我如何代表一个具有数十种关系的复杂资源”。我实际上找不到关于这个主题的很多文章/资源。如果我只是引用ID,那不是很安静吗? - Layke
绝对没错。我唯一能确保的是你传输对象图的整个表示而不仅仅是部分量。当然,您可以使用您的方法“超级纯粹”并将您的单个POST调用降级为大量POST调用(每个对象需要创建一个)但我认为这将是一个任意决定,只会强迫你要做几十个 - 如果不是几百个 - 远程呼叫。这实际上取决于您的应用程序需要什么。 - Brian Kelly


答案:


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

/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"
  ..
}

布伦特伍德的特点:

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。看到 REST中的PUT与POST

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


10
2018-04-02 15:21





我想你真的在问,“我如何以适合在POST中传输的形式表示复杂数据?”,对吧?它与REST关系不大,而与您选择的媒体类型有关。我建议从纯JSON表示开始,使用数组和交叉引用的ID字段来映射关系。当然,您也可以使用XML执行此操作。

你给出的例子看起来对钱。您只需要确保双方(浏览器和服务器)就您使用的媒体类型的结构和解释达成一致。


3
2018-03-24 22:31



布赖恩,是的,你是对的。我的问题实际上归结为:“我如何代表一个具有数十种关系的复杂资源”。我实际上找不到关于这个主题的很多文章/资源。如果我只是引用ID,那不是很安静吗? - Layke
绝对没错。我唯一能确保的是你传输对象图的整个表示而不仅仅是部分量。当然,您可以使用您的方法“超级纯粹”并将您的单个POST调用降级为大量POST调用(每个对象需要创建一个)但我认为这将是一个任意决定,只会强迫你要做几十个 - 如果不是几百个 - 远程呼叫。这实际上取决于您的应用程序需要什么。 - Brian Kelly


我正在处理完全相同的事情。我选择不在任何地方使用id,但是在任何地方都使用url通常会被期望。

所以在你的情况下,kitchenfeatures可能只是一个带有url的数组:

/feature/1
/feature/23

和主题

/propertyTheme/12
/propertyTheme/32
etc..

在多对多关系的情况下,我们更新所有关系作为一个整体。通常我们只是转储现有数据,并插入新关系。

对于一对多关系,我们有时会在有意义的地方扩展网址。如果您要在“属性”上拥有评论功能,这可能就像

/property/1/comment/5

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

这对你有帮助吗?


2
2018-03-30 10:42



这是否意味着您的客户端向服务器指示它必须为每个新创建的对象使用哪个URI?这是我试图避免的,因为应该是服务器决定URI的样子。或者您的客户端是否已经从之前的POST中获得了这些URI? - Brian Kelly
既然你在谈论多对多,那么我就已经存在与你有关的(特征)。所以客户会有那些uri可用。这个假设是错的吗? - Evert
我想我们需要OP来回答这个问题。我假设相反,客户基本上是一举创建一个完整的图形。 - Brian Kelly