2015-10-02 46 views
3

这个问题是语言无关。让我们不用担心框架或实现,让我们说一切都可以实现,让我们以抽象的方式看待REST API。换句话说:我现在正在构建一个框架,并且我没有看到任何地方的任何解决方案。如何构建REST超媒体API中的交集?

问题

一个可以如何构建两个独立的REST蹊径返回集合的交集REST URL终点?短的例子:如何相交/users/1/comments/companies/6/comments

约束

所有终端应该返回单一数据模型实体或实体的集合。

恕我直言,这是一个非常合理的约束和超媒体的API的所有例子是这样的,即使是在draft-kelly-json-hal-07

如果你认为这是一个无效的约束,或者您知道更好的方法,请让我知道。

所以我们可以说我们已经有三个数据类型的应用程序:productscategoriescompanies。每个公司都可以将一些产品添加到他们的资料页面在添加产品时,他们必须在产品上附加一个类别。例如,我们可以访问这种数据是这样的:

  • GET /categories将返回所有类别
  • GET /categories/9将返回ID的类别9
  • GET /categories/9/products将返回所有的产品里面的id类的集合9
  • GET /companies/7/products将返回所有产品添加到ID 7的公司档案页面

我省略了_links超媒体部分,因为它很直接,例如/给出_links/categories/companies等。我们只需要记住,通过使用超媒体我们遍历关系图。

如何写URL将返回:即从公司(7),并类别(9)的所有产品?换句话说,如何相交/categories/9/products/companies/7/products

假设所有端点都应该代表数据模型资源或它们的集合,我相信这是REST超媒体API的一个基本问题,因为在遍历超媒体API时,我们正在遍历关系图向下走一条路径,所以不可能描述这样的因为它是两个独立图形路径的横截面。

换句话说,我认为,我们不能代表只有一个通道两个独立的路径。通常我们遍历一条路径,如A->B->C,但如果我们有X->YZ->Y,并且我们希望所有来自XZY都有问题。

到目前为止,我的建议是使用查询字符串:/categories/9/products?intersect=/companies/9,但我们可以做得更好吗?

为什么我要这个?

因为我构建了一个基于SQL数据库关系自动生成REST Hypermedia API的框架。您可以将其视为一个到SELECT ... JOIN ... WHERE查询的URL转换编译器,但API的客户端只能看到超媒体,并且客户端想要有一个很好的交点的方式,就像这个例子。

回答

2

我不认为你应该总是把REST看作是数据库表示,这种情况看起来更像是一种特定的功能。我想我会像这样的东西去:

/intersection/comments?company=9&product=5

我已经挖后,我写的,这就是我发现(http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api):

有时候你真的无法将操作映射到合理的RESTful结构。例如,多资源搜索对于应用于特定资源的端点没有意义。在这种情况下,即使它不是资源,/ search也是最有意义的。这没什么 - 只要从API消费者的角度做正确的事情,并确保它清楚记录以避免混淆。

+0

你是否建议客户端没有魔幻ID的9&5?这不是很RESTful –

1

什么,你想要做的是过滤产品的类别之一......那么下面你举的例子,如果我们有:

GET /categories/9/products 

以上将返回所有产品在9类,所以筛选出的产品为公司7我会用这样的

GET /categories/9/products?company=7 

你应该把URI为纽带,以获取所有数据(就像在SQL简单的选择查询)和查询参数s作为where,limit,desc等 使用此方法您可以构建复杂且可读的查询fe。

GET /categories/9/products?company=7&order=name,asc&offset=10&limit=20 
1

所有终端应该返回单一数据模型实体或 实体的集合。

这不是REST约束。如果您想了解REST约束,请阅读Fielding dissertation

因为我正在构建一个框架,它将自动生成REST 基于SQL数据库关系的超媒体API。

这是一种错误的方法,与REST无关。

通过REST,您可以通过在响应中发送超链接描述可能的资源状态转换(或操作调用模板)。如果您使用HTTP和URI标准构建统一接口,这些超链接由HTTP方法和URI(以及其他与此无关的数据)组成,我们通常会这样做。这些URI不是(必然)是数据库实体和集合标识符,如果您应用了这样的约束,您将最终得到一个CRUD API,而不是使用REST API。

如果您无法使用HTTP方法和现有资源的组合来描述操作,那么您需要一个新资源。

你的情况,你要聚集GET /users/1/commentsGET /companies/6/comments的反应,所以你需要定义与获得一个链接和第三资源:

GET /comments/?users=1&companies=6 
GET /intersection/users:1/companies:6/comments 
GET /intersection/users/1/companies/6/comments 

等等

1

RESTful架构约为返回包含提供状态转换的超媒体控件的资源。我在这里看到的是一个多步骤的状态转换过程。假设您有一个根资源并以某种方式使用可用的超媒体控件导航到/categories/9/products。我可以打赌,结果会是这个样子的HAL:

{ 
    _links : { 
    self : { href : "/categories/9/products"} 
    }, 
    _embedded : { 
    item : [ 
     {json of prod 1}, 
     {json of prod 2} 
    ] 
    } 
} 

如果你希望你的客户端能够与您需要向他们提供执行该机构另一个集合相交这一点。你必须给他们一个超媒体控制。 HAL只有链接,模板链接,并嵌入为控件类型。让我们一起去links..change应对:

{ 
    _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。