ReST-PUT与PATCH,以在添加新属性时最大程度地减少客户端与API之间的耦合

问题描述 投票:1回答:1

我们正在构建一组新的REST API。

假设我们有一个包含以下字段的资源/users

{
  id: 1
  email: "[email protected]"
}

客户端实现此API,然后可以通过向PUT /users/1发送新的资源表示来更新此资源。

现在让我们像这样向模型添加一个新属性name

{
  id: 1
  email: "[email protected]"
  name: "test user"
}

如果现有客户端使用的模型将调用我们的API而不更新,则对PUT /users/1的调用将删除新的name属性,因为PUT应该替换资源。我知道客户端可以直接使用原始json来确保他们总是收到API中添加的任何新属性,但这是很多额外的工作,在正常情况下,客户端将创建其自己拥有API资源的模型表示。这意味着,每当添加任何新属性时,所有客户端都需要更新其一侧的代码/模型,以确保它们不会意外删除属性。这会在系统之间造成不必要的耦合。

作为解决此问题的一种方法,我们正在考虑完全不执行PUT操作,并将更新切换到PATCH,在该更新中,未传入的属性完全不变。从技术上讲,这似乎是正确的,但可能不符合REST的精神。我还稍微担心客户对PATCH动词的支持。

其他人如何解决这个问题?这是最佳做法吗?

rest patch put
1个回答
0
投票

PUT切换到PATCH不会解决您的问题,IMO。 IMO的根本原因是,客户已经考虑将返回的数据用于某种特定类型的表示形式。根据菲尔丁

REST API永远不应具有对客户端重要的“类型化”资源。(Source

而不是使用typed resources,客户端应使用内容类型协商来交换数据。这里,足以普遍采用的媒体类型格式肯定是有益的,但是某些领域可能需要更具体的表示格式。

想像一个汽车供应商网页,您可以在其中从首选汽车中检索数据。作为人类,您可以轻松地识别出数据代表的是典型的汽车。但是,您很可能以(HTML)格式接收数据的媒体类型不会通过其语法或元素的语义来说明该数据描述了汽车,除非存在某些语义注释属性或元素,尽管您可能更新数据或在其他地方使用数据。

这是可能的,因为HTML附带了丰富的元素和属性规范,例如Web forms,它不仅描述了受支持的或期望的输入参数,而且还描​​述了将数据发送到的URI,以及要用于的表示格式发送(由application/x-www-form-urlencoded隐式指定;但是可能会被enctype属性覆盖)或要使用的HTTP方法,该方法在HTML中固定为GETPOST。通过这种方式,服务器能够教客户如何建立请求。因此,客户端除了必须了解HTTP,URI和HTML规范之外,不需要了解其他任何信息。

由于网页通常充满各种不相关的内容,例如添加,样式信息或脚本以及XML(-like)语法,因此并不是每个人都喜欢的,因为它可能会增加实际有效负载的大小稍微地,大多数所谓的“ REST” API确实希望交换基于JSON的文档。尽管纯JSON不是理想的表示格式,但它根本不带有链接支持,但它非常流行。某些附加内容,例如JSON Hyper-Schemaapplication/schema+json hyper-schema)或JSON Hypertext Application-Language (HAL)application/hal+json),增加了对链接和链接关系的支持。这些可用于呈现从服务器as-is接收的数据。但是,如果您希望响应自动驱动您的应用程序状态(即使用处理后的数据动态绘制GUI),则需要一种更具体的表示格式,该格式可由您的客户端解析并在了解服务器所需内容时采取相应措施它与此有关(= affordance)。如果您想指导客户如何建立请求,则需要支持对其他媒体类型(例如hal-formsion)的支持。此外,某些媒体类型允许您使用称为配置文件的概念,该概念允许您使用语义类型注释资源。 HAL JSON即确实支持类似的内容,其中Content-Type标头现在可能包含诸如application/hal+json;profile=http://schema.org/Car的值,这暗示媒体类型处理器有效负载遵循给定profile的定义,因此可以应用进一步的有效性检查。

由于表示形式的格式应该足够通用才能获得广泛的使用,并且URI本身也不应暗示客户端期望什么样的数据,因此需要使用其他机制。链接关系名称基本上是URI的注释,它可以告知客户端某个链接的用途。一个可分页的集合可能返回标有firstprevnextlast的链接,它们的作用很明显。其他链接可能会用prefetch提示,这暗示客户端可以在加载完当前资源后立即加载资源,因为客户端很可能会在下一次检索此资源。但是,此类媒体类型应为standardized(在提案或RFC中定义并在IANA中注册)或遵循Web linking提出的模式(即Dublin Core使用的模式)。如果服务器更改其URI方案而不是尝试从URI本身解析某些参数,则仅将URI用于调用的链接关系名称的客户端仍然可以工作。

关于在分布式系统中解耦/耦合,必须存在一定数量的耦合,否则各方将根本无法进行通信。尽管这里的重点是,耦合应该基于许多客户端可以支持的定义良好的标准格式,而不是仅交换有限数量的客户端支持的特定表示格式(在最坏的情况下,只有自己的客户端)。现在应该直接在各方可以用来交换格式的媒体类型上发生耦合,而不是直接耦合到API并使用未定义的基于JSON的语法(可能带有相应字段语义的外部文档)。在这里,不是要问支持哪种媒体类型的问题,而是要支持多少个问题。客户端或服务器支持的媒体类型越多,与分布式系统中其他对等方进行交互的可能性就越大。从总体上看,您希望服务器能够为大量客户端提供服务,而单个客户端应该能够(最好)与每台服务器进行交互,而无需不断采用。

因此,如果您确实希望将客户端与服务器脱钩,则应仔细研究Web的实际工作方式,并尝试将其交互模型模仿到您的应用程序层上。正如“鲍勃叔叔”罗伯特·C·马丁提到的]]

一种架构与意图有关! (Source

REST体系结构的目的是使客户端与服务器/服务脱钩。因此,支持多种媒体类型(或定义自己的通用类型,足以被广泛采用),仅通过其随附的链接关系名称来查找URI,并依赖于内容类型协商,并且仅依赖于提供的数据可以帮助您达到所需的去耦程度。

© www.soinside.com 2019 - 2024. All rights reserved.