RESTful API 设计更新 1/多对多关系的最佳实践?
Posted
技术标签:
【中文标题】RESTful API 设计更新 1/多对多关系的最佳实践?【英文标题】:Best practice for RESTful API design updating 1/many-to-many relationship? 【发布时间】:2019-07-04 20:01:12 【问题描述】:假设我有一个食谱页面,其中的食谱可以有许多与之相关的成分。用户可以编辑成分列表并更新/保存食谱。在数据库中有这些表:食谱表、配料表、配料表。假设一个食谱有成分 a、b、c、d,但随后用户将其更改为 a、d、e、f。通过对服务器的请求,我是否只发送新的成分列表并让后端确定需要删除/插入数据库的值?或者我是否在有效负载中明确说明需要删除哪些值以及需要插入哪些值?我猜它可能是前者,但是这是在数据库查询之前或期间处理的吗?我是先从表格中读取然后在计算差异后写入吗?或者查询只是处理这个?
我搜索并看到涉及 INSERT IGNORE... + DELETE ... NOT IN ... 或使用 MERGE 语句的解决方案。该项目没有使用 ORM——我认为这可以通过 ORM 轻松完成吗?
【问题讨论】:
【参考方案1】:您能分享一下用户界面的外观吗?您可以将单个新成分作为操作发布或删除一个作为操作,这将是非常标准的做法。您可以简单地在成分旁边有一个按钮来发起 DELETE 请求,并在下方有一个用于 POST 的表单。
让用户输入一个列表会产生不必要的复杂性。
【讨论】:
我还没有实现它,但我正在考虑删除和添加在您单击编辑按钮后出现的按钮。然后是推动批量更改的保存按钮。每次用户单击删除/添加时,将删除/添加作为单独的请求会更好吗? 是的。这是标准做法。但是你绝对可以让你的表单和删除按钮只有在你点击编辑按钮时才会出现。这可能是一个很好的功能。【参考方案2】:一种常见的模式是将其视为远程创作问题。
远程创作的基本思想是我们向服务器询问其当前资源的表示。然后我们对表示进行本地(对客户端)编辑,然后请求服务器接受我们的表示作为替代。
所以我们可以GET
一个包含 JSON 成分数组的表示。在我们的本地副本中,我们删除我们不再需要的成分,添加新的成分。我们会将PUT
我们的本地副本返回到服务器。
当文档非常大,并且更改很容易描述时,我们可能不会将整个文档发送到服务器,而是发送一个 PATCH 请求,其中包含描述我们在本地所做的更改的“补丁文档”。
当服务器只是一个文档存储时,服务器上的实现很容易——您可以查看更改以确定它们是否有效,计算新的表示(如果需要),然后将其保存到文件中,或其他。
当您使用关系数据库时?然后服务器实现需要弄清楚如何更新自己。 ORM 库可能会为您节省大量工作,但不能保证——人们往往会纠结于“对象关系映射器”的“对象”端。您可能需要退回到手动滚动您自己的 SQL。
远程创作的替代方法是将问题视为网站。在这种情况下,您将获得某种形式的表示,允许客户端描述应进行的更改,然后提交该表单,生成描述预期更改的 POST 请求。
但是您在服务器端遇到了同样的映射问题——您需要做多少工作才能将 POST 请求转换为正确的数据库事务?
REST 并没有告诉您如何将请求中提供的表示形式转换为您的关系数据库。毕竟,这是要点的一部分——REST旨在允许您在不破坏现有客户端的情况下用替代实现替换服务器,反之亦然。
也就是说,是的 - 你的基本想法是正确的;您可能只是替换数据库中的整个现有表示,或者您可能改为优化以仅发布必要的更改。 ORM 可能能够为您有效地执行转换——众所周知,延迟加载等优化会使事情变得非常复杂。
【讨论】:
哦,实际上我想问另一个问题,但最终省略了与 RESTful 位相关的问题。如果每个食谱有许多成分和许多作者,并且我想获取食谱列表(分页),我是否会有 3 个 API 端点来获取食谱,然后根据食谱 ID 获取成分和作者?或者 1 个端点会获取加入其他 2 个表的食谱?还是我会实现一个视图并获取它?以上是关于RESTful API 设计更新 1/多对多关系的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章
EF Core 5.0 - 更新 ASP.NET Core Web API 中的多对多实体