4

这个问题与语言无关。让我们不要担心框架或实现,我们只是说一切都可以实现,让我们以抽象的方式看待 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->Y并且Z->Y我们想要所有Y来自的 s,X那么Z我们就会遇到问题。

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

我为什么要这个?

因为我正在构建一个框架,它将基于 SQL 数据库关系自动生成 REST 超媒体 API。您可以将其视为SELECT ... JOIN ... WHERE查询 URL 的反编译器,但 API 的客户端只看到超媒体,并且客户端希望有一种很好的方式来进行交叉,就像在示例中一样。

4

4 回答 4

3

我认为您不应该总是将 REST 视为数据库表示,这种情况对我来说更像是一种特定的功能。我想我会选择这样的东西:

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

我写完之后一直在挖掘,这就是我发现的(http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api):

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

于 2015-10-03T07:46:52.330 回答
2

您想要做的是过滤其中一个类别的产品......所以如果我们有,请按照您的示例:

GET /categories/9/products

以上将返回类别 9 中的所有产品,因此要过滤掉公司 7 的产品,我会使用类似这样的东西

GET /categories/9/products?company=7

您应该将 URI 视为获取所有数据的链接(就像 SQL 中的简单选择查询)并将查询参数视为 where、limit、desc 等。使用这种方法您可以构建复杂且可读的查询 fe。

GET /categories/9/products?company=7&order=name,asc&offset=10&limit=20
于 2015-10-03T10:09:36.807 回答
1

所有端点都应返回单个数据模型实体或实体集合。

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

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

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

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

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

在您的情况下,您想要聚合GET /users/1/commentsGET /companies/6/comments响应,因此您需要使用 GET 和第三个资源定义链接:

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

ETC...

于 2015-10-06T17:25:13.237 回答
1

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

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

于 2015-10-17T04:08:16.303 回答