REST API 架构:如何表示连接表

Mik*_*ing 17 sql sql-server rest api-design

我有一个复杂的查询,它连接三个表并返回一组行,每行都有来自它的同级表的数据。如何以 RESTful 方式表示这一点?

FWIW 我知道不一定有“正确”的方法来做到这一点,但我有兴趣了解什么可能是这种情况下最可扩展和最持久的解决方案。

背景

在过去,我代表了或多或少反映了 url 字面结构的单个表。例如,该 urlGET /agents/1/policies将导致类似select * from policies where agent_id = 1.

假设

似乎 url 不一定必须与数据库层的结构如此紧密地耦合。例如,如果复杂查询类似于:

select
  agent.name as agent_name,
  policy.status as policy_status,
  vehicle.year as vehicle_year
from
  policies as policy
  join agents as agent on policy.agent_id = agent.id
  join vehicles as vehicle on vehicle.policy_id = policy.id
where 1=1
  and policy.status = 'active';

# outputs something like:
{ "agent_name": "steve", "policy_status": "single", "vehicle_year": "1999" }
Run Code Online (Sandbox Code Playgroud)

我可以将此 QUERY 表示为 url 而不是 TABLES 表示为 url。这个 url 可以是/vehicles,如果有人想要查询它(使用 id 或其他一些参数,如/vehicles?vehicle_color=red),我可以将该值传递到准备好的语句中。

奖金问题

  • 这是反模式吗?
  • 我的查询是否应该始终针对 EXISTING 表而不是准备好的语句运行?

谢谢你的帮助!

gvi*_*iew 13

您想从数据库表和查询​​中退后一步,考虑基本资源。在您的示例中,显然这些是agent,customer vehiclepolicy

资源与集合

我在您的示例中看到的一个错误是,您没有使用复数将集合与资源分开,这在您处理搜索和逻辑处理时非常有用,对于您的控制器路由。在您的示例中,您有:

GET /agents/1/policies

相反,假设这是GET /agent/1/policies

现在,您可以清楚地区分幂等资源的位置: /agent/1和查找/搜索代理集合: /agents

遵循这一序列,您开始将枚举关系与 API 中关系的每一侧分离,这在本质上是多余的。

在您的示例中,显然策略不是由代理专门拥有的。策略应该是一种独立的资源,可通过一些幂等 url 使用任何 ID 唯一标识该策略以查找该策略,即。 /policy/{Id}

搜索集合

这现在为您所做的是允许您通过以下方式分离策略的发现: /policies仅返回特定代理的策略只是您可能访问该集合的多种不同方式之一。

因此,与其让GET /agents/1/policies 您通过以下方式找到与代理关联的策略: GET /policies?agent=1

预期结果将是匹配策略的资源标识符集合:

{ "policies" : ["/policy/234234", "/policy/383282"] }
Run Code Online (Sandbox Code Playgroud)

那么如何得到最终结果呢?

对于给定的策略,您希望完整返回关联信息,就像在您的查询中一样,只是没有 select 子句的限制。由于您想要的是过滤版本,因此处理该问题的方法是包含过滤条件。

GET /policy/234234?filter=agentName,policyStatus,vehicleYear

话虽如此,这种方法有缺陷,我出于多种原因质疑这种方法。如果您查看原始资源列表,您会发现每个资源都可以视为一个对象。如果您在客户端构建对象图,则策略的完整信息将包括所有关联资源的资源定位符:

{ ... Policy data + "customer": "/customer/2834", "vehicle": "/vehicle/88328", "agent": "/agent/32" }
Run Code Online (Sandbox Code Playgroud)

客户的工作是访问代理、车辆和客户的数据,而不是在您需要查看这些数据的任何时候冗余地重新生成所有这些数据的工作。

这更好,因为它既是宁静的,又支持 REST 的许多目标,以支持幂等性、缓存等。

这也更好地允许客户端在本地缓存 Agent 的数据,并确定它是否需要获取该数据或仅访问它已经缓存的数据。在最坏的情况下,可能需要进行 3 或 4 个 REST 调用。

奖金问题

REST 有一些灰色地带。你必须解释菲尔丁,因此,关于如何做事经常有不同的意见。虽然GET /agents/1/policies经常使用提供 api 的方法来提供与代理关联的策略列表,但在我的经验中,有一点变得限制和冗余,因为它需要最终用户熟悉您的建模方式与底层资源的关系。

至于您关于查询的问题,只要您保持一致,访问底层数据和组织它的方式没有区别。经常发生的事情(出于性能目的)是 api 不返回资源标识符并开始返回数据,如我之前所示。这是一个滑坡,您只是将 REST api 变成了一堆查询的前端,此时您的 API 可能只是: GET \query?filter=agent.name, policy.status, vehicle.year&from=policies&join=agents,vehicles&where=...

  • 抱歉,您的回复已经一年了,但我只想说谢谢您给出这样的想法!我肯定会在我的下一个 api 上重新审视你的建议。 (3认同)