“过滤器作为资源”是一个完美的技巧。
您可以将过滤器定义放到过滤器资源中,它可以返回过滤器ID。
PUT 是幂等的,因此即使过滤器已经存在,您只需要检测到您之前看过过滤器,就可以为过滤器返回正确的 ID。
然后,您可以向其他请求添加过滤器参数,它们可以获取过滤器以用于查询。
GET /medications?filter=1234&page=4&pagesize=20
我会通过某种规范化过程运行原始过滤器,只是为了获得一个标准化集,例如过滤器“firstname=Bob lastname=Eubanks”与“lastname=Eubanks firstname=Bob”相同。但这只是我。
唯一真正担心的是,随着时间的推移,您可能需要淘汰一些过滤器。如果有人使用缺少或过时的过滤器提出请求,您可以简单地出错。
编辑回答问题...
让我们从基础开始。
简单地说,您想指定一个用于查询的过滤器,但这些过滤器(可能)涉及且复杂。如果是简单的 /medications/1234,这不会有问题。
实际上,您始终需要将过滤器发送到查询。问题是如何表示该过滤器。
REST 系统中的会话之类的基本问题是它们通常是“带外”管理的。例如,当您去创建药物时,您可以 PUT 或 POST 到药物资源,然后您会获得对该药物的引用。
通过会话,您(通常)会取回一个 cookie,或者可能是其他一些表示该会话的令牌。如果您对药物资源的 PUT 也创建了一个会话,那么实际上,您的请求创建了两个资源:一个药物和一个会话。
不幸的是,当您使用 cookie 之类的东西,并且您的请求需要该 cookie 时,资源名称不再是资源的真实表示。现在是资源名称(URL)和 cookie。
所以,如果我对名为 /medications/search 的资源执行 GET,并且 cookie 代表一个会话,并且该会话恰好有一个过滤器,您可以看到该资源名称 /medications 的效果如何/search,根本没用。由于 cookie 和会话以及其中的过滤器的副作用,我没有有效使用所需的所有信息。
现在,您或许可以重写名称:/medications/search?session=ABC123,有效地将 cookie 嵌入到资源名称中。
但是现在您遇到了典型的会话合同,特别是它们的寿命很短。因此,该命名资源不太有用,长期而言,不是没用,只是不太有用。现在,这个查询给了我有趣的数据。明天?可能不是。我会收到一些关于会话消失的严重错误。
另一个问题是会话通常不作为资源进行管理。例如,它们通常是副作用,而不是通过 GET/PUT/DELETE 显式管理。会话也是 Web 应用程序状态的“垃圾堆”。在这种情况下,我们只是希望会话正确填充此请求所需的内容。我们实际上并不知道。同样,这是一个副作用。
现在,让我们稍微改变一下。让我们使用 /medications/search?filter=ABC123。
显然,随便,这看起来是一样的。我们只是将名称从“会话”更改为“过滤器”。但是,正如所讨论的,在这种情况下,过滤器是“一流的资源”。它们需要像药物、JPEG 或系统中的任何其他资源一样创建、管理等。这是关键区别。
当然,您可以将“会话”视为一流资源,创建它们,直接将内容放入其中等。但是您可以看到,至少从清晰的角度来看,“一流”会话是如何对于这种情况,这并不是一个很好的抽象。使用会话,就像去清洁工并交出您的整个钱包或公文包。 “是的,票就在某处,挖出你想要的,把我的衣服给我”,尤其是与像过滤器这样的明确的东西相比。
因此,您可以看到,在 30,000 英尺处,过滤器和会话之间的情况并没有太大区别。但是当你放大时,它们就完全不同了。
使用过滤器资源,您可以选择让它们成为永久的东西。你可以让它们过期,你可以做任何你想做的事情。会话往往具有预先设想的语义:短暂的生命、连接的持续时间等。过滤器可以具有您想要的任何语义。它们与会话所附带的完全不同。
如果我这样做,我将如何使用过滤器?
我会假设我真的不关心过滤器的内容。具体来说,我怀疑我是否会查询“所有按名字搜索的过滤器”。在这个关头,它似乎是无趣的信息,所以我不会围绕它进行设计。
接下来,我将规范化过滤器,就像我上面提到的那样。确保等效过滤器确实是等效的。您可以通过对表达式进行排序、确保字段名全部为大写或其他方式来做到这一点。
然后,我会将过滤器存储为 XML 或 JSON 文档,以更适合/适合应用程序为准。我会给每个过滤器一个唯一的键(自然),但我也会用过滤器存储实际文档的哈希值。
我这样做是为了能够快速找到过滤器是否已存储。由于我正在对其进行规范化,因此我“知道”逻辑等效过滤器的 XML(例如)将是相同的。所以,当有人去 PUT 或插入一个新的过滤器时,我会检查散列以查看它之前是否已存储。我可能会返回多个(当然,哈希可能会发生冲突),所以我需要检查实际的 XML 有效负载以查看它们是否匹配。
如果过滤器匹配,我会返回对现有过滤器的引用。如果没有,我会创建一个新的并返回它。
我也不允许过滤器 UPDATE/POST。因为我分发了对这些过滤器的引用,所以我会让它们不可变,这样引用就可以保持有效。如果我想要按“角色”进行过滤,例如“获取所有过期药物过滤器”,那么我将创建一个“命名过滤器”资源,将名称与过滤器实例相关联,以便实际过滤器数据可以更改,但名称保持不变。
另外请注意,在创建过程中,您处于竞争状态(两个请求试图创建相同的过滤器),因此您必须考虑到这一点。如果您的系统具有高过滤量,这可能是一个潜在的瓶颈。
希望这可以为您澄清问题。