将资源链接到另一个资源时使用 POST 路由

using a POST route when linking a resource to another one

假设您有两个实体 ProductCategory。一个产品可以有多个类别,一个类别可以有多个产品。

当谈到 API 设计时,您想要创建端点以在产品中添加/删除类别。第一种方法是这个

这很好,但我通常使用 POST 创建新资源并发回 201。另一种方法是

如果您想添加/删除它,请发送一个布尔值。第二种方法似乎更合适(只是 return 一个 200)但是主体有效载荷看起来有点难看。

{
    "add": true
}

或者在没有主体有效负载的情况下调用补丁路由,然后切换它?如果该产品链接到类别,请将其删除,否则添加。

从另一个资源中添加/删除资源的最佳做法是什么?

我建议您阅读 Jim Webber 的 2011 talk

如果我们在做 REST,那么我们就是在使用通用消息语义来实现我们的目标。当 HTTP 是我们选择的应用程序时,我们的通用消息语义是那些与通过网络传输文档相关联的语义。

您通过对资源提出更改建议来向系统传递信息。

一种常见的更改形式是修改资源的表示形式。在您的情况下,这将建议一个资源,该资源是与产品关联的所有类别的列表。因此,您将 GET 该资源的当前表示,对您的副本进行本地更改,然后 PUT 您更新后的表示返回到相同的资源。

GET /products/1/categories
200 OK
Content-Type: text/plain

A
B
C
D
PUT /products/1/categories
Content-Type: text/plain

A
B
E
F
G
200 OK

当资源的表示非常大(相对于 HTTP headers 的大小),而你想要支持的编辑通常会很小,那么支持就有意义了PATCH,接受一种标准化的补丁文档格式。

另一种方法是 POST 给资源一个描述要进行的某些更改的文档。参见 It is okay to use POST,罗伊·菲尔丁 (Roy Fielding):

POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”

大多数 pre-javascript HTML 网络都是这样工作的; HTML 表单会告诉客户如何创建目标资源知道如何解释的 application/x-www-form-urlencoded 文档。

POST /products/1/categories
Content-Type: application/x-www-form-urlencoded

remove=C,D&add=E,F,G

效果很好;网络取得了灾难性的成功。

表单之所以有效,是因为 text/html 媒体类型具有标准化的表单定义以及处理方式。您可以对自己的媒体类型做类似的事情;在表示中定义如何找到有趣的 link 来宣传某些资源的功能。

另一种方法是使用[web links];您定义 link 关系

的语义

the relation http://example.org/abc indicates that the target resource is capable of understanding and handling POST requests containing application/prs.xyz+json documents)

然后您将这些 link 关系嵌入到您的表示中,嵌入到 HTTP headers 中,或同时嵌入到两者中。然后,任何了解 link 关系语义和相关媒体类型的客户端都将能够利用所宣传的功能。

请参阅 RFC 5023 了解如何在 Atom 中应用此方法。