这个问题与语言无关。让我们不要担心框架或实现,让我们说一切都可以实现,让我们以抽象的方式看待REST API。换句话说:我现在正在构建一个框架,而且我在任何地方都没有看到任何解决这个问题的方法。
问题
如何为两个返回集合的独立REST路径的交集构建REST URL端点?简短示例:如何交叉/users/1/comments
和/companies/6/comments
?
约束
所有端点都应返回单个数据模型实体或实体集合。
Imho这是一个非常合理的约束,所有超媒体API的例子都是这样的,即使在draft-kelly-json-hal-07中也是如此。
如果您认为这是一个无效的约束,或者您知道更好的方法,请告诉我。
示例
因此,我们假设我们的应用程序有三种数据类型:products
,categories
和companies
。每家公司都可以在其个人资料页面中添加一些产品添加产品时,必须在产品中附加类别。例如,我们可以访问这样的数据:
GET /categories
将返回所有类别的集合GET /categories/9
将返回id 9 GET /categories/9/products
将返回id 9 GET /companies/7/products
将返回添加到id 7 我故意省略_links
超媒体部分,因为它很简单,例如/
将_links
提供给/categories
和{{1}我们只需要记住,通过使用超媒体,我们遍历关系图。
如何编写将返回的网址:所有来自公司(7)且属于类别(9)的产品?换句话说,如何交叉/companies
和/categories/9/products
?
假设所有端点都应该代表数据模型资源或它们的集合我相信这是REST超媒体API的一个基本问题,因为在遍历超媒体api时,我们遍历一条路径的关系图,因此不可能描述这样的交集因为它是两个独立图形路径的横截面。
换句话说,我认为我们不能代表只有一条路径的两条独立路径。通常我们遍历一条路径,例如/companies/7/products
,但如果我们有A->B->C
和X->Y
,我们希望所有来自Z->Y
和Y
的{{1}}那我们就有问题了。
到目前为止,我的主张是使用查询字符串:X
但我们可以做得更好吗?
为什么我要这个?
因为我正构建一个框架,它将根据SQL数据库关系自动生成REST Hypermedia API。您可以将其视为Z
查询的URL的转换编译器,但API的客户端只能看到超媒体,并且客户端希望有一种很好的交叉方式,如示例中所示。
答案 0 :(得分:2)
我认为你不应该总是将REST视为数据库表示,这种情况对我来说更像是一种特定的功能。我想我会选择这样的东西:
/intersection/comments?company=9&product=5
我写完之后就一直在挖掘,这就是我发现的(http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api):
有时候你真的无法将动作映射到合理的RESTful结构。例如,多资源搜索实际上没有意义应用于特定资源的端点。在这种情况下,即使它不是资源,/ search也会最有意义。这没关系 - 只需从API使用者的角度做正确的事情,并确保明确记录以避免混淆。
答案 1 :(得分:1)
您要做的是过滤其中一个类别中的产品......如果我们有以下内容,请按照您的示例进行操作:
GET /categories/9/products
以上将返回第9类中的所有产品,因此要过滤掉公司7的产品,我会使用类似的产品
GET /categories/9/products?company=7
您应该将URI视为获取所有数据的链接(就像SQL中的简单选择查询一样),并将查询参数视为where,limit,desc等。 使用此方法您可以构建复杂且可读的查询。
GET /categories/9/products?company=7&order=name,asc&offset=10&limit=20
答案 2 :(得分:1)
所有端点都应返回单个数据模型实体或集合 实体。
这不是REST约束。如果您想了解REST约束,请阅读Fielding dissertation。
因为我正在构建一个自动生成REST的框架 基于SQL数据库关系的超媒体API。
这是一种错误的方法,与REST无关。
通过REST,您可以通过在响应中发送超链接来描述可能的资源状态转换(或操作调用模板)。如果您使用HTTP和URI标准构建统一接口,这些超链接由HTTP方法和URI(以及其他现在不相关的数据)组成,我们通常会这样做。 URI不是(必然)数据库实体和集合标识符,如果应用这样的约束,最终将使用CRUD API,而不是REST API。
如果您无法使用HTTP方法和现有资源的组合来描述操作,那么您需要一个新资源。
在您的情况下,您希望汇总GET /users/1/comments
和GET /companies/6/comments
个回复,因此您需要定义与GET和第三个资源的链接:
GET /comments/?users=1&companies=6
GET /intersection/users:1/companies:6/comments
GET /intersection/users/1/companies/6/comments
等...
答案 3 :(得分:1)
RESTful架构是关于返回包含提供状态转换的超媒体控件的资源。我在这里看到的是状态转换的多步骤过程。假设您有一个根资源,并使用可用的超媒体控件以某种方式导航到/categories/9/products
。我敢打赌结果看起来像是这样的:
{
_links : {
self : { href : "/categories/9/products"}
},
_embedded : {
item : [
{json of prod 1},
{json of prod 2}
]
}
}
如果您希望客户端能够将其与另一个集合交叉,则需要向他们提供执行此操作的机制。你必须给他们一个超媒体控制。 HAL只有链接,模板化链接和嵌入式控件类型。让我们使用链接..将响应更改为:
{
_links : {
self : { href : "/categories/9/products"},
x:intersect-with : [
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 1",
title : "Company 6 products"
},
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 2",
title : "Company 5 products"
},
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 3",
title : "Company 7 products"
}
]
},
_embedded : {
item : [
{json of prod 1},
{json of prod 2}
]
}
}
现在,客户端只根据链接的标题字段选择正确的超媒体控件(也就是链接)。
这是最简单的解决方案。但是你可能会说1000多家公司我不想要1000个链接......好吧,如果那样的话,那真的是这样......你呢只是在我们的两个中间提供一个状态转换:
{
_links : {
self : { href : "/categories/9/products"},
x:intersect-options : { href : "URL to a Paged collection of all intersect options"},
x:intersect-with : [
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 1",
title : "Company 6 products"
},
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 2",
title : "Company 5 products"
},
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 3",
title : "Company 7 products"
}
]
},
_embedded : {
item : [
{json of prod 1},
{json of prod 2}
]
}
}
看看我在那里做了什么?额外的状态转换的额外控制。只要你有一个网页,就像你会做的那样。你可能会把它放在弹出窗口中,以及你的应用程序的客户端也可以使用该控件的结果。
真的那么简单......只要想想你是如何用HTML做的并做同样的事情。
这里的一大好处是,客户永远不需要知道公司或类别ID,或者将其插入某个模板。 id是实现细节,客户端永远不知道它们存在,它们只是执行了超媒体控件......而且是RESTful。