用于过滤的多个资源上的 RESTful API 多个查询字符串

Posted

技术标签:

【中文标题】用于过滤的多个资源上的 RESTful API 多个查询字符串【英文标题】:RESTful API Multiple Query Strings over multiple Resources for Filtering 【发布时间】:2018-02-05 16:18:54 【问题描述】:

假设有一个实体公司和一个实体国家。一个公司可以属于多个国家,一个国家可以有多个公司。因此,对于公司来说,有一个具有不同角色的中间表成员资格,例如一家公司是一个国家的制造商,而另一家公司是一个国家的供应商。一个国家可以有多种状态,例如 is_active 等。

现在我们要从角色为制造商且国家状态为 is_active = false 的特定公司获取所有国家/地区。

RESTful API 端点如何查找此用例?是否允许过滤多个资源?一些想法:

GET /companies/id/nations?role=manufacturer&is_active=false

GET /memberships/id/nations?role=manufacturer&is_active=false

更新 也许我的问题不够清楚。查询字符串参数在两个不同的表/实体中进行查找。角色在成员资格实体内,而 is_active 在国家实体内。我认为只允许对请求的资源进行过滤。也许我可以把这个问题分成两个用例。

1) 使用 URI 中的中间资源是否“更好”? 2) 我们可以在多个表/实体上过滤带有查询字符串参数的资源吗?

【问题讨论】:

这完全取决于您作为 API 设计器如何实现它。 REST 不关心 URI 的外观,因为 URI 的语义是在关系本身中提供的。 【参考方案1】:

REST 不在乎您对标识符使用什么拼写。任何编码到 URI 中的数据都由服务器自行决定并供其使用。

这基本上意味着只要您的 URI 符合 RFC 3986,您就做对了。这意味着:

Hierarchical data 属于路径 - 允许通用客户端以正确的方式解析相对引用。非分层数据属于查询。

是否允许过滤多个资源?

其他方式 - 标识符与可能从多行数据加载/过滤状态的单个资源匹配。

GET /companies/id/nations?role=manufacturer&is_active=false
GET /companies/id/nations?role=manufacturer&is_active=true

这是两个不同的资源;它们恰好由相同的参数化查询支持这一事实是一个实现细节。

查询字符串参数在两个不同的表/实体中进行查找。

这是一个实现细节。就 API 使用者而言,您可能只是从键值存储中提取准备好的文档。

这是重点的一部分——即使底层实现需要更改,API 也应该是稳定的。将集成接口与当前数据模式紧密耦合会使向后兼容的更改更加困难。

我认为只允许对请求的资源进行过滤。

没有。就 REST 而言,整个 URI 是一个标识符。客户端使用该 URI 来访问和操作资源。对于资源的实现在接口后面的样子,绝对没有 REST 约束。它可以是文档存储、单个表、许多表、第 3 方服务,以及所有这些的某种组合......

您用来提供当前表示的服务器端框架可能会关心 - 某些标识符比其他标识符更适合您的路由策略,该框架可能会将您限制为数据需要存储在一个地方的约定.但这些都只是实现细节。 REST 不在乎。

我们可以在多个表/实体上过滤带有查询字符串参数的资源吗?

“过滤资源”的拼写并不完全正确,因为它会将您的集成资源(REST 关心的东西)与您的数据模型混淆。

能否从存储在多个表中的数据创建单个资源的表示?当然。是否可以将资源限制为来自那些满足某些过滤规范的表中的数据?当然。对哪些过滤器可以应用于哪些表有任何限制吗?没有。

吉姆·韦伯:

URI 不映射到域对象 - 这违反了封装...。您应该期望集成域中的资源比业务域中的业务对象多得多。

【讨论】:

@DehMotth ad 1) 关于 URI 内部的逻辑没有对错之分,因此这个问题相当基于意见。广告 2) 是什么阻止您这样做?您还可以查看矩阵参数,您可以在其中直接在相应段上指定参数,而不是在末尾附加它们。不过,由于您已经指定了一个具体的 ID,我不确定在这种特殊情况下进一步过滤机制的有用性【参考方案2】:

这是一个在 SlashDB 中实现的固执己见的答案。

考虑一下这种情况,它与您的情况非常相似:

曲目 -- 播放列表

一个曲目可以位于多个播放列表中,一个播放列表通常由许多曲目组成。下面的 URL 是可点击的,并将显示资源的 html 表示:

这里是播放列表“古典”的 URI:

https://demo.slashdb.com/db/Chinook/Playlist/Name/Classical

现在,让我们转到传递表 PlaylistTrack

https://demo.slashdb.com/db/Chinook/Playlist/Name/Classical/PlaylistTrack

由于 PlaylistTrack 与 Track 有关系,我们可以将其添加为最后一段:

https://demo.slashdb.com/db/Chinook/Playlist/Name/Classical/PlaylistTrack/Track

您可以选择遵循相同的模式。当一般实现时,它将允许对您的数据模型进行非常惊人的过滤和遍历。

例如,让我们在古典播放列表中查找曲目的发票,但只查找来自法国、奥地利或意大利的曲目,以及总金额在 3 到 10 美元之间的曲目。

https://demo.slashdb.com/db/Chinook/Playlist/Name/Classical/PlaylistTrack/Track/InvoiceLine/Invoice/BillingCountry/France,Austria,Italy/Total/3..10

【讨论】:

以上是关于用于过滤的多个资源上的 RESTful API 多个查询字符串的主要内容,如果未能解决你的问题,请参考以下文章

Flask-RESTful API:多个复杂的端点

多对多资源映射restful api设计

具有多租户和共享资源的 RESTful API

如何在 RESTful API 中处理多对多关系?

Restful API 特性详解

Restful api 和搜索和邀请等操作